3 #############################################################################
5 ## scapy.py --- Interactive packet manipulation tool ##
6 ## see http://www.secdev.org/projects/scapy/ ##
7 ## for more informations ##
9 ## Copyright (C) 2003 Philippe Biondi <phil@secdev.org> ##
11 ## This program is free software; you can redistribute it and/or modify it ##
12 ## under the terms of the GNU General Public License version 2 as ##
13 ## published by the Free Software Foundation; version 2. ##
15 ## This program is distributed in the hope that it will be useful, but ##
16 ## WITHOUT ANY WARRANTY; without even the implied warranty of ##
17 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ##
18 ## General Public License for more details. ##
20 #############################################################################
23 from __future__ import generators
28 DEFAULT_CONFIG_FILE = os.path.join(os.environ["HOME"], ".scapy_startup.py")
31 os.stat(DEFAULT_CONFIG_FILE)
33 DEFAULT_CONFIG_FILE = None
36 print """Usage: scapy.py [-s sessionfile] [-c new_startup_file] [-C]
37 -C: do not read startup file"""
41 #############################
42 ##### Logging subsystem #####
43 #############################
45 class Scapy_Exception(Exception):
48 import logging,traceback,time
50 class ScapyFreqFilter(logging.Filter):
52 logging.Filter.__init__(self)
53 self.warning_table = {}
54 def filter(self, record):
55 wt = conf.warning_threshold
57 stk = traceback.extract_stack()
63 tm,nb = self.warning_table.get(caller, (0,0))
72 record.msg = "more "+record.msg
75 self.warning_table[caller] = (tm,nb)
78 log_scapy = logging.getLogger("scapy")
79 console_handler = logging.StreamHandler()
80 console_handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
81 log_scapy.addHandler(console_handler)
82 log_runtime = logging.getLogger("scapy.runtime") # logs at runtime
83 log_runtime.addFilter(ScapyFreqFilter())
84 log_interactive = logging.getLogger("scapy.interactive") # logs in interactive functions
85 log_loading = logging.getLogger("scapy.loading") # logs when loading scapy
87 if __name__ == "__main__":
95 import socket, sys, getopt, string, struct, random, code
96 import cPickle, copy, types, gzip, base64, re, zlib, array
98 from select import select
100 from fcntl import ioctl
104 warnings.filterwarnings("ignore","tempnam",RuntimeWarning, __name__)
111 log_loading.info("did not find python gnuplot wrapper . Won't be able to plot")
118 log_loading.info("Can't import PyX. Won't be able to use psdump() or pdfdump()")
122 LINUX=sys.platform.startswith("linux")
123 OPENBSD=sys.platform.startswith("openbsd")
124 FREEBSD=sys.platform.startswith("freebsd")
125 DARWIN=sys.platform.startswith("darwin")
126 BIG_ENDIAN= struct.pack("H",1) == "\x00\x01"
127 X86_64 = (os.uname()[4] == 'x86_64')
128 SOLARIS=sys.platform.startswith("sunos")
143 log_loading.warning("did not find pcap module. Fallback to linux primitives")
146 if __name__ == "__main__":
147 log_loading.error("did not find pcap module")
158 log_loading.warning("did not find dnet module. Fallback to linux primitives")
161 if __name__ == "__main__":
162 log_loading.error("did not find dnet module")
168 f = os.popen("tcpdump -V 2> /dev/null")
169 if f.close() >> 8 == 0x7f:
170 log_loading.warning("Failed to execute tcpdump. Check it is installed and in the PATH")
179 from Crypto.Cipher import ARC4
181 log_loading.info("Can't find Crypto python lib. Won't be able to decrypt WEP")
184 # Workarround bug 643005 : https://sourceforge.net/tracker/?func=detail&atid=105470&aid=643005&group_id=5470
186 socket.inet_aton("255.255.255.255")
189 if x == "255.255.255.255":
192 return socket.inet_aton(x)
194 inet_aton = socket.inet_aton
196 inet_ntoa = socket.inet_ntoa
198 inet_ntop = socket.inet_ntop
199 inet_pton = socket.inet_pton
200 except AttributeError:
201 log_loading.info("inet_ntop/pton functions not found. Python IPv6 support not present")
205 # GRE is missing on Solaris
206 socket.IPPROTO_GRE = 47
208 ###############################
209 ## Direct Access dictionnary ##
210 ###############################
213 if x and x[0] in "0123456789":
215 return x.translate("________________________________________________0123456789_______ABCDEFGHIJKLMNOPQRSTUVWXYZ______abcdefghijklmnopqrstuvwxyz_____________________________________________________________________________________________________________________________________")
218 class DADict_Exception(Scapy_Exception):
222 def __init__(self, _name="DADict", **kargs):
224 self.__dict__.update(kargs)
225 def fixname(self,val):
227 def __contains__(self, val):
228 return val in self.__dict__
229 def __getitem__(self, attr):
230 return getattr(self, attr)
231 def __setitem__(self, attr, val):
232 return setattr(self, self.fixname(attr), val)
234 return iter(map(lambda (x,y):y,filter(lambda (x,y):x and x[0]!="_", self.__dict__.items())))
236 for k in self.__dict__.keys():
237 if k and k[0] != "_":
238 print "%10s = %r" % (k,getattr(self,k))
240 return "<%s/ %s>" % (self._name," ".join(filter(lambda x:x and x[0]!="_",self.__dict__.keys())))
242 def _branch(self, br, uniq=0):
243 if uniq and br._name in self:
244 raise DADict_Exception("DADict: [%s] already branched in [%s]" % (br._name, self._name))
247 def _my_find(self, *args, **kargs):
248 if args and self._name not in args:
251 if k not in self or self[k] != kargs[k]:
255 def _find(self, *args, **kargs):
256 return self._recurs_find((), *args, **kargs)
257 def _recurs_find(self, path, *args, **kargs):
260 if self._my_find(*args, **kargs):
263 if isinstance(o, DADict):
264 p = o._recurs_find(path+(self,), *args, **kargs)
268 def _find_all(self, *args, **kargs):
269 return self._recurs_find_all((), *args, **kargs)
270 def _recurs_find_all(self, path, *args, **kargs):
274 if self._my_find(*args, **kargs):
277 if isinstance(o, DADict):
278 p = o._recurs_find_all(path+(self,), *args, **kargs)
282 return filter(lambda x:x and x[0]!="_", self.__dict__.keys())
291 ETHER_BROADCAST = "\xff"*6
301 ARPHDR_LOOPBACK = 772
305 SIOCGIFHWADDR = 0x8927 # Get hardware address
306 SIOCGIFADDR = 0x8915 # get PA address
307 SIOCGIFNETMASK = 0x891b # get network PA mask
308 SIOCGIFNAME = 0x8910 # get iface name
309 SIOCSIFLINK = 0x8911 # set iface channel
310 SIOCGIFCONF = 0x8912 # get iface list
311 SIOCGIFFLAGS = 0x8913 # get flags
312 SIOCSIFFLAGS = 0x8914 # set flags
313 SIOCGIFINDEX = 0x8933 # name -> if_index mapping
314 SIOCGIFCOUNT = 0x8938 # get number of devices
315 SIOCGSTAMP = 0x8906 # get packet timestamp (as a timeval)
319 IFF_UP = 0x1 # Interface is up.
320 IFF_BROADCAST = 0x2 # Broadcast address valid.
321 IFF_DEBUG = 0x4 # Turn on debugging.
322 IFF_LOOPBACK = 0x8 # Is a loopback net.
323 IFF_POINTOPOINT = 0x10 # Interface is point-to-point link.
324 IFF_NOTRAILERS = 0x20 # Avoid use of trailers.
325 IFF_RUNNING = 0x40 # Resources allocated.
326 IFF_NOARP = 0x80 # No address resolution protocol.
327 IFF_PROMISC = 0x100 # Receive all packets.
331 # From netpacket/packet.h
332 PACKET_ADD_MEMBERSHIP = 1
333 PACKET_DROP_MEMBERSHIP = 2
334 PACKET_RECV_OUTPUT = 3
336 PACKET_STATISTICS = 6
337 PACKET_MR_MULTICAST = 0
338 PACKET_MR_PROMISC = 1
339 PACKET_MR_ALLMULTI = 2
345 SO_ATTACH_FILTER = 26
349 RTF_UP = 0x0001 # Route usable
353 #BIOCIMMEDIATE=0x80044270
354 BIOCIMMEDIATE=-2147204496
359 # file parsing to get some values :
361 def load_protocols(filename):
362 spaces = re.compile("[ \t]+|\n")
363 dct = DADict(_name=filename)
365 for l in open(filename):
373 lt = tuple(re.split(spaces, l))
374 if len(lt) < 2 or not lt[0]:
376 dct[lt[0]] = int(lt[1])
378 log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e))
380 log_loading.info("Can't open /etc/protocols file")
383 IP_PROTOS=load_protocols("/etc/protocols")
385 def load_ethertypes(filename):
386 spaces = re.compile("[ \t]+|\n")
387 dct = DADict(_name=filename)
398 lt = tuple(re.split(spaces, l))
399 if len(lt) < 2 or not lt[0]:
401 dct[lt[0]] = int(lt[1], 16)
403 log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e))
409 ETHER_TYPES=load_ethertypes("/etc/ethertypes")
411 def load_services(filename):
412 spaces = re.compile("[ \t]+|\n")
413 tdct=DADict(_name="%s-tcp"%filename)
414 udct=DADict(_name="%s-udp"%filename)
425 lt = tuple(re.split(spaces, l))
426 if len(lt) < 2 or not lt[0]:
428 if lt[1].endswith("/tcp"):
429 tdct[lt[0]] = int(lt[1].split('/')[0])
430 elif lt[1].endswith("/udp"):
431 udct[lt[0]] = int(lt[1].split('/')[0])
433 log_loading.warning("Couldn't file [%s]: line [%r] (%s)" % (filename,l,e))
436 log_loading.info("Can't open /etc/services file")
439 TCP_SERVICES,UDP_SERVICES=load_services("/etc/services")
441 class ManufDA(DADict):
442 def fixname(self, val):
444 def _get_manuf_couple(self, mac):
445 oui = ":".join(mac.split(":")[:3]).upper()
446 return self.__dict__.get(oui,(mac,mac))
447 def _get_manuf(self, mac):
448 return self._get_manuf_couple(mac)[1]
449 def _get_short_manuf(self, mac):
450 return self._get_manuf_couple(mac)[0]
451 def _resolve_MAC(self, mac):
452 oui = ":".join(mac.split(":")[:3]).upper()
454 return ":".join([self[oui][0]]+ mac.split(":")[3:])
460 def load_manuf(filename):
462 manufdb=ManufDA(_name=filename)
463 for l in open(filename):
466 if not l or l.startswith("#"):
468 oui,shrt=l.split()[:2]
474 manufdb[oui] = shrt,lng
476 log_loading.warning("Couldn't parse one line from [%s] [%r] (%s)" % (filename, l, e))
478 #log_loading.warning("Couldn't open [%s] file" % filename)
482 MANUFDB = load_manuf("/usr/share/wireshark/wireshark/manuf")
495 if (j < 32) or (j >= 127):
496 r=r+conf.color_theme.not_printable(".")
505 if (j < 32) or (j >= 127):
512 if type(x) in (int,long):
514 elif type(x) is tuple:
515 return "(%s)" % ", ".join(map(lhex, x))
516 elif type(x) is list:
517 return "[%s]" % ", ".join(map(lhex, x))
529 print "%02X" % ord(x[i+j]),
535 print sane_color(x[i:i+16])
538 def linehexdump(x, onlyasc=0, onlyhex=0):
543 print "%02X" % ord(x[i]),
550 print ", ".join(map(lambda x: "%#04x"%ord(x), x))
552 def hexstr(x, onlyasc=0, onlyhex=0):
555 s.append(" ".join(map(lambda x:"%02x"%ord(x), x)))
568 for j in range(len(y)):
569 d[-1,j] = d[-1,j-1][0]+INSERT, (-1,j-1)
570 for i in range(len(x)):
571 d[i,-1] = d[i-1,-1][0]+INSERT, (i-1,-1)
573 for j in range(len(y)):
574 for i in range(len(x)):
575 d[i,j] = min( ( d[i-1,j-1][0]+SUBST*(x[i] != y[j]), (i-1,j-1) ),
576 ( d[i-1,j][0]+INSERT, (i-1,j) ),
577 ( d[i,j-1][0]+INSERT, (i,j-1) ) )
584 while not (i == j == -1):
586 backtrackx.append(x[i2+1:i+1])
587 backtracky.append(y[j2+1:j+1])
593 colorize = { 0: lambda x:x,
594 -1: conf.color_theme.left,
595 1: conf.color_theme.right }
602 linex = backtrackx[i:i+16]
603 liney = backtracky[i:i+16]
604 xx = sum(len(k) for k in linex)
605 yy = sum(len(k) for k in liney)
609 if dox and linex == liney:
618 print colorize[doy-dox]("%04x" % xd),
629 print colorize[doy-dox]("%04x" % yd),
641 col = colorize[(linex[j]!=liney[j])*(doy-dox)]
642 print col("%02X" % ord(line[j])),
643 if linex[j]==liney[j]:
644 cl += sane_color(line[j])
646 cl += col(sane(line[j]))
674 if len(pkt) % 2 == 1:
676 s = sum(array.array("H", pkt))
677 s = (s >> 16) + (s & 0xffff)
683 if len(pkt) % 2 == 1:
685 s = sum(array.array("H", pkt))
686 s = (s >> 16) + (s & 0xffff)
689 return (((s>>8)&0xff)|s<<8) & 0xffff
692 log_runtime.warning(x)
695 return "".join(map(lambda x: chr(int(x,16)), mac.split(":")))
698 return ("%02x:"*6)[:-1] % tuple(map(ord, s))
701 return "".join(map(lambda x,y:chr(ord(x)^ord(y)),x,y))
707 ip = inet_aton(socket.gethostbyname(x))
708 return struct.unpack("!I", ip)[0]
710 return inet_ntoa(struct.pack("!I", x))
713 return (0xffffffff00000000L>>x)&0xffffffffL
715 def do_graph(graph,prog=None,format="svg",target=None, type=None,string=None,options=None):
716 """do_graph(graph, prog=conf.prog.dot, format="svg",
717 target="| conf.prog.display", options=None, [string=1]):
718 string: if not None, simply return the graph string
719 graph: GraphViz graph description
720 format: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option
721 target: filename or redirect. Defaults pipe to Imagemagick's display program
722 prog: which graphviz program to use
723 options: options to be passed to prog"""
733 target = "| %s" % conf.prog.display
734 if format is not None:
735 format = "-T %s" % format
736 w,r = os.popen2("%s %s %s %s" % (prog,options or "", format or "", target))
741 "{":"{\\tt\\char123}",
742 "}":"{\\tt\\char125}",
743 "\\":"{\\tt\\char92}",
751 "|":"{\\tt\\char124}",
752 "~":"{\\tt\\char126}",
753 "<":"{\\tt\\char60}",
754 ">":"{\\tt\\char62}",
760 s += _TEX_TR.get(c,c)
763 def colgen(*lstcol,**kargs):
764 """Returns a generator that mixes provided quantities forever
765 trans: a function to convert the three arguments into a color. lambda x,y,z:(x,y,z) by default"""
768 trans = kargs.get("trans", lambda x,y,z: (x,y,z))
770 for i in range(len(lstcol)):
771 for j in range(len(lstcol)):
772 for k in range(len(lstcol)):
773 if i != j or j != k or k != i:
774 yield trans(lstcol[(i+j)%len(lstcol)],lstcol[(j+k)%len(lstcol)],lstcol[(k+i)%len(lstcol)])
776 def incremental_label(label="tag%05i", start=0):
781 #########################
782 #### Enum management ####
783 #########################
787 def __init__(self, key, value):
791 return "<%s %s[%r]>" % (self.__dict__.get("_name", self.__class__.__name__), self._key, self._value)
792 def __getattr__(self, attr):
793 return getattr(self._value, attr)
796 def __eq__(self, other):
797 return self._value == int(other)
800 class Enum_metaclass(type):
801 element_class = EnumElement
802 def __new__(cls, name, bases, dct):
804 for k,v in dct.iteritems():
806 v = cls.element_class(k,v)
809 dct["__rdict__"] = rdict
810 return super(Enum_metaclass, cls).__new__(cls, name, bases, dct)
811 def __getitem__(self, attr):
812 return self.__rdict__[attr]
813 def __contains__(self, val):
814 return val in self.__rdict__
815 def get(self, attr, val=None):
816 return self._rdict__.get(attr, val)
818 return "<%s>" % self.__dict__.get("name", self.__name__)
823 ##############################
824 ## Session saving/restoring ##
825 ##############################
828 def save_session(fname, session=None, pickleProto=-1):
830 session = scapy_session
832 to_be_saved = session.copy()
834 if to_be_saved.has_key("__builtins__"):
835 del(to_be_saved["__builtins__"])
837 for k in to_be_saved.keys():
838 if type(to_be_saved[k]) in [types.TypeType, types.ClassType, types.ModuleType]:
839 log_interactive.error("[%s] (%s) can't be saved." % (k, type(to_be_saved[k])))
843 os.rename(fname, fname+".bak")
846 f=gzip.open(fname,"wb")
847 cPickle.dump(to_be_saved, f, pickleProto)
850 def load_session(fname):
852 s = cPickle.load(gzip.open(fname,"rb"))
854 s = cPickle.load(open(fname,"rb"))
855 scapy_session.clear()
856 scapy_session.update(s)
858 def update_session(fname):
860 s = cPickle.load(gzip.open(fname,"rb"))
862 s = cPickle.load(open(fname,"rb"))
863 scapy_session.update(s)
866 def export_object(obj):
867 print base64.encodestring(gzip.zlib.compress(cPickle.dumps(obj,2),9))
869 def import_object(obj=None):
871 obj = sys.stdin.read()
872 return cPickle.loads(gzip.zlib.decompress(base64.decodestring(obj.strip())))
875 def save_object(fname, obj):
876 cPickle.dump(obj,gzip.open(fname,"wb"))
878 def load_object(fname):
879 return cPickle.load(gzip.open(fname,"rb"))
882 ######################
883 ## Extension system ##
884 ######################
887 def load_extension(filename):
889 paths = conf.extensions_paths
890 if type(paths) is not list:
893 name = os.path.realpath(os.path.expanduser(filename))
894 thepath = os.path.dirname(name)
895 thename = os.path.basename(name)
896 if thename.endswith(".py"):
897 thename = thename[:-3]
899 paths.insert(0, thepath)
904 syspath = sys.path[:]
907 extf = imp.find_module(thename, paths)
909 log_runtime.error("Module [%s] not found. Check conf.extensions_paths ?" % filename)
911 ext = imp.load_module(thename, *extf)
913 __builtin__.__dict__.update(ext.__dict__)
937 """Add more powers to a class that have a "src" attribute."""
939 os.system("whois %s" % self.src)
941 t = [32,64,128,255]+[self.ttl]
943 return t[t.index(self.ttl)+1]
945 return self.ottl()-self.ttl-1
948 ##############################
949 ## Routing/Interfaces stuff ##
950 ##############################
955 self.s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
958 def invalidate_cache(self):
962 self.invalidate_cache()
963 self.routes = read_routes()
966 rt = "Network Netmask Gateway Iface Output IP\n"
967 for net,msk,gw,iface,addr in self.routes:
968 rt += "%-15s %-15s %-15s %-15s %-15s\n" % (ltoa(net),
975 def make_route(self, host=None, net=None, gw=None, dev=None):
978 elif net is not None:
979 thenet,msk = net.split("/")
982 raise Scapy_Exception("make_route: Incorrect parameters. You should specify a host or a net")
990 dev,ifaddr,x = self.route(nhop)
992 ifaddr = get_if_addr(dev)
993 return (atol(thenet), itom(msk), gw, dev, ifaddr)
995 def add(self, *args, **kargs):
997 add(net="192.168.1.0/24",gw="1.2.3.4")
999 self.invalidate_cache()
1000 self.routes.append(self.make_route(*args,**kargs))
1003 def delt(self, *args, **kargs):
1004 """delt(host|net, gw|dev)"""
1005 self.invalidate_cache()
1006 route = self.make_route(*args,**kargs)
1008 i=self.routes.index(route)
1011 warning("no matching route found")
1013 def ifchange(self, iff, addr):
1014 self.invalidate_cache()
1015 the_addr,the_msk = (addr.split("/")+["32"])[:2]
1016 the_msk = itom(int(the_msk))
1017 the_rawaddr = atol(the_addr)
1018 the_net = the_rawaddr & the_msk
1021 for i in range(len(self.routes)):
1022 net,msk,gw,iface,addr = self.routes[i]
1026 self.routes[i] = (the_net,the_msk,gw,iface,the_addr)
1028 self.routes[i] = (net,msk,gw,iface,the_addr)
1029 for i in arp_cache.keys():
1034 def ifdel(self, iff):
1035 self.invalidate_cache()
1037 for rt in self.routes:
1039 new_routes.append(rt)
1040 self.routes=new_routes
1042 def ifadd(self, iff, addr):
1043 self.invalidate_cache()
1044 the_addr,the_msk = (addr.split("/")+["32"])[:2]
1045 the_msk = itom(int(the_msk))
1046 the_rawaddr = atol(the_addr)
1047 the_net = the_rawaddr & the_msk
1048 self.routes.append((the_net,the_msk,'0.0.0.0',iff,the_addr))
1051 def route(self,dest,verbose=None):
1052 if dest in self.cache:
1053 return self.cache[dest]
1056 # Transform "192.168.*.1-5" to one IP of the set
1057 dst = dest.split("/")[0]
1058 dst = dst.replace("*","0")
1063 m = (dst[l:]+".").find(".")
1064 dst = dst[:l]+dst[l+m:]
1069 for d,m,gw,i,a in self.routes:
1072 pathes.append((0xffffffffL,("lo",a,"0.0.0.0")))
1073 if (dst & m) == (d & m):
1074 pathes.append((m,(i,a,gw)))
1077 warning("No route found (no default route?)")
1078 return "lo","0.0.0.0","0.0.0.0" #XXX linux specific!
1079 # Choose the more specific route (greatest netmask).
1080 # XXX: we don't care about metrics
1083 self.cache[dest] = ret
1086 def get_if_bcast(self, iff):
1087 for net, msk, gw, iface, addr in self.routes:
1088 if (iff == iface and net != 0L):
1089 bcast = atol(addr)|(~msk&0xffffffffL); # FIXME: check error in atol()
1091 warning("No broadcast address found for iface %s\n" % iff);
1094 def get_if_raw_hwaddr(iff):
1096 return (772, '\x00'*6)
1098 l = dnet.intf().get(iff)
1101 raise Scapy_Exception("Error in attempting to get hw address for interface [%s]" % iff)
1102 return l.type,l.data
1103 def get_if_raw_addr(ifname):
1105 return i.get(ifname)["addr"].data
1107 def get_if_raw_hwaddr(iff):
1108 return struct.unpack("16xh6s8x",get_if(iff,SIOCGIFHWADDR))
1110 def get_if_raw_addr(iff):
1112 return get_if(iff, SIOCGIFADDR)[20:24]
1119 # remove 'any' interface
1120 return map(lambda x:x[0],filter(lambda x:x[1] is None,pcap.findalldevs()))
1121 def get_working_if():
1123 return pcap.lookupdev()
1127 def attach_filter(s, filter):
1128 warning("attach_filter() should not be called in PCAP mode")
1129 def set_promisc(s,iff,val=1):
1130 warning("set_promisc() should not be called in DNET/PCAP mode")
1134 f=open("/proc/net/dev","r")
1139 lst.append(l.split(":")[0].strip())
1141 def get_working_if():
1142 for i in get_if_list():
1145 ifflags = struct.unpack("16xH14x",get_if(i,SIOCGIFFLAGS))[0]
1146 if ifflags & IFF_UP:
1149 def attach_filter(s, filter):
1150 # XXX We generate the filter on the interface conf.iface
1151 # because tcpdump open the "any" interface and ppp interfaces
1152 # in cooked mode. As we use them in raw mode, the filter will not
1153 # work... one solution could be to use "any" interface and translate
1154 # the filter from cooked mode to raw mode
1159 f = os.popen("%s -i %s -ddd -s 1600 '%s'" % (conf.prog.tcpdump,conf.iface,filter))
1161 log_interactive.warning("Failed to execute tcpdump: (%s)")
1163 lines = f.readlines()
1165 raise Scapy_Exception("Filter parse error")
1169 bpf += struct.pack("HBBI",*map(long,l.split()))
1171 # XXX. Argl! We need to give the kernel a pointer on the BPF,
1172 # python object header seems to be 20 bytes. 36 bytes for x86 64bits arch.
1174 bpfh = struct.pack("HL", nb, id(bpf)+36)
1176 bpfh = struct.pack("HI", nb, id(bpf)+20)
1177 s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, bpfh)
1179 def set_promisc(s,iff,val=1):
1180 mreq = struct.pack("IHH8s", get_if_index(iff), PACKET_MR_PROMISC, 0, "")
1182 cmd = PACKET_ADD_MEMBERSHIP
1184 cmd = PACKET_DROP_MEMBERSHIP
1185 s.setsockopt(SOL_PACKET, cmd, mreq)
1190 def new_read_routes():
1198 print r.loop(addrt, rtlst)
1203 f=os.popen("netstat -rvn") # -f inet
1205 f=os.popen("netstat -rnW") # -W to handle long interface names
1207 f=os.popen("netstat -rn") # -f inet
1211 for l in f.readlines():
1215 if l.find("----") >= 0: # a separation line
1217 if l.find("Destination") >= 0:
1219 if l.find("Mtu") >= 0:
1227 dest,mask,gw,netif,mxfrg,rtt,ref,flg = l.split()[:8]
1230 dest,gw,flg,ref,use,mtu,netif = l.split()[:7]
1232 dest,gw,flg,ref,use,netif = l.split()[:6]
1233 if flg.find("Lc") >= 0:
1235 if dest == "default":
1240 netmask = atol(mask)
1242 dest,netmask = dest.split("/")
1243 netmask = itom(int(netmask))
1245 netmask = itom((dest.count(".") + 1) * 8)
1246 dest += ".0"*(3-dest.count("."))
1250 ifaddr = get_if_addr(netif)
1251 routes.append((dest,netmask,gw,netif,ifaddr))
1255 def read_interfaces():
1259 if not iff.has_key("addr"):
1261 if not iff.has_key("link_addr"):
1263 rawip = iff["addr"].data
1264 ip = inet_ntoa(rawip)
1265 rawll = iff["link_addr"].data
1267 lst[iff["name"]] = (rawll,ll,rawip,ip)
1268 i.loop(addif, ifflist)
1275 f=open("/proc/net/route","r")
1277 s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
1278 ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x","lo"))
1279 addrfamily = struct.unpack("h",ifreq[16:18])[0]
1280 if addrfamily == socket.AF_INET:
1281 ifreq2 = ioctl(s, SIOCGIFNETMASK,struct.pack("16s16x","lo"))
1282 msk = socket.ntohl(struct.unpack("I",ifreq2[20:24])[0])
1283 dst = socket.ntohl(struct.unpack("I",ifreq[20:24])[0]) & msk
1284 ifaddr = inet_ntoa(ifreq[20:24])
1285 routes.append((dst, msk, "0.0.0.0", "lo", ifaddr))
1287 warning("Interface lo: unkown address family (%i)"% addrfamily)
1289 for l in f.readlines()[1:]:
1290 iff,dst,gw,flags,x,x,x,msk,x,x,x = l.split()
1291 flags = int(flags,16)
1292 if flags & RTF_UP == 0:
1294 if flags & RTF_REJECT:
1297 ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x",iff))
1298 except IOError: # interface is present in routing tables but does not have any assigned IP
1301 addrfamily = struct.unpack("h",ifreq[16:18])[0]
1302 if addrfamily == socket.AF_INET:
1303 ifaddr = inet_ntoa(ifreq[20:24])
1305 warning("Interface %s: unkown address family (%i)"%(iff, addrfamily))
1307 routes.append((socket.htonl(long(dst,16))&0xffffffffL,
1308 socket.htonl(long(msk,16))&0xffffffffL,
1309 inet_ntoa(struct.pack("I",long(gw,16))),
1315 def get_if(iff,cmd):
1317 ifreq = ioctl(s, cmd, struct.pack("16s16x",iff))
1322 def get_if_index(iff):
1323 return int(struct.unpack("I",get_if(iff, SIOCGIFINDEX)[16:20])[0])
1325 def get_last_packet_timestamp(sock):
1326 ts = ioctl(sock, SIOCGSTAMP, "12345678")
1327 s,us = struct.unpack("II",ts)
1328 return s+us/1000000.0
1331 def get_if_addr(iff):
1332 return inet_ntoa(get_if_raw_addr(iff))
1334 def get_if_hwaddr(iff):
1335 addrfamily, mac = get_if_raw_hwaddr(iff)
1336 if addrfamily in [ARPHDR_ETHER,ARPHDR_LOOPBACK]:
1339 raise Scapy_Exception("Unsupported address family (%i) for interface [%s]" % (addrfamily,iff))
1343 #####################
1344 ## ARP cache stuff ##
1345 #####################
1349 # XXX Fill arp_cache with /etc/ether and arp cache
1352 if 0 and DNET: ## XXX Can't use this because it does not resolve IPs not in cache
1353 dnet_arp_object = dnet.arp()
1354 def getmacbyip(ip, chainCC=0):
1355 tmp = map(ord, inet_aton(ip))
1356 if (tmp[0] & 0xf0) == 0xe0: # mcast @
1357 return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3])
1358 iff,a,gw = conf.route.route(ip)
1360 return "ff:ff:ff:ff:ff:ff"
1363 res = dnet_arp_object.get(dnet.addr(ip))
1369 def getmacbyip(ip, chainCC=0):
1370 tmp = map(ord, inet_aton(ip))
1371 if (tmp[0] & 0xf0) == 0xe0: # mcast @
1372 return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3])
1373 iff,a,gw = conf.route.route(ip)
1374 if ( (iff == "lo") or (ip == conf.route.get_if_bcast(iff)) ):
1375 return "ff:ff:ff:ff:ff:ff"
1379 if arp_cache.has_key(ip):
1380 mac, timeout = arp_cache[ip]
1381 if not timeout or (time.time()-timeout < ARPTIMEOUT):
1384 res = srp1(Ether(dst=ETHER_BROADCAST)/ARP(op="who-has", pdst=ip),
1392 mac = res.payload.hwsrc
1393 arp_cache[ip] = (mac,time.time())
1398 ####################
1399 ## Random numbers ##
1400 ####################
1402 def randseq(inf, sup, seed=None, forever=1, renewkeys=0):
1403 """iterate through a sequence in random order.
1404 When all the values have been drawn, if forever=1, the drawing is done again.
1405 If renewkeys=0, the draw will be in the same order, guaranteeing that the same
1406 number will be drawn in not less than the number of integers of the sequence"""
1407 rnd = random.Random(seed)
1422 if turns == 0 or renewkeys:
1423 sbox = [rnd.randint(0,fsmask) for k in xrange(sbox_size)]
1429 for k in range(rounds): # Unbalanced Feistel Network
1432 lsb ^= sbox[ct%sbox_size]
1441 class VolatileValue:
1443 return "<%s>" % self.__class__.__name__
1444 def __getattr__(self, attr):
1445 if attr == "__setstate__":
1446 raise AttributeError(attr)
1447 return getattr(self._fix(),attr)
1452 class RandField(VolatileValue):
1456 class RandNum(RandField):
1459 def __init__(self, min, max):
1460 self.seq = randseq(min,max)
1462 return self.seq.next()
1464 class RandNumGamma(RandField):
1465 def __init__(self, alpha, beta):
1469 return int(round(random.gammavariate(self.alpha, self.beta)))
1471 class RandNumGauss(RandField):
1472 def __init__(self, mu, sigma):
1476 return int(round(random.gauss(self.mu, self.sigma)))
1478 class RandNumExpo(RandField):
1479 def __init__(self, lambd):
1482 return int(round(random.expovariate(self.lambd)))
1484 class RandByte(RandNum):
1486 RandNum.__init__(self, 0, 2L**8-1)
1488 class RandShort(RandNum):
1490 RandNum.__init__(self, 0, 2L**16-1)
1492 class RandInt(RandNum):
1494 RandNum.__init__(self, 0, 2L**32-1)
1496 class RandSInt(RandNum):
1498 RandNum.__init__(self, -2L**31, 2L**31-1)
1500 class RandLong(RandNum):
1502 RandNum.__init__(self, 0, 2L**64-1)
1504 class RandSLong(RandNum):
1506 RandNum.__init__(self, -2L**63, 2L**63-1)
1508 class RandChoice(RandField):
1509 def __init__(self, *args):
1511 raise TypeError("RandChoice needs at least one choice")
1514 return random.choice(self._choice)
1516 class RandString(RandField):
1517 def __init__(self, size, chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"):
1522 for i in range(self.size):
1523 s += random.choice(self.chars)
1526 class RandBin(RandString):
1527 def __init__(self, size):
1528 RandString.__init__(self, size, "".join(map(chr,range(256))))
1531 class RandTermString(RandString):
1532 def __init__(self, size, term):
1533 RandString.__init__(self, size, "".join(map(chr,range(1,256))))
1536 return RandString._fix(self)+self.term
1540 class RandIP(RandString):
1541 def __init__(self, iptemplate="0.0.0.0/0"):
1542 self.ip = Net(iptemplate)
1544 return self.ip.choice()
1546 class RandMAC(RandString):
1547 def __init__(self, template="*"):
1548 template += ":*:*:*:*:*"
1549 template = template.split(":")
1552 if template[i] == "*":
1554 elif "-" in template[i]:
1555 x,y = template[i].split("-")
1556 v = RandNum(int(x,16), int(y,16))
1558 v = int(template[i],16)
1561 return "%02x:%02x:%02x:%02x:%02x:%02x" % self.mac
1564 class RandOID(RandString):
1565 def __init__(self, fmt=None, depth=RandNumExpo(0.1), idnum=RandNumExpo(0.01)):
1568 fmt = fmt.split(".")
1569 for i in range(len(fmt)):
1571 fmt[i] = tuple(map(int, fmt[i].split("-")))
1576 if self.ori_fmt is None:
1577 return "<%s>" % self.__class__.__name__
1579 return "<%s [%s]>" % (self.__class__.__name__, self.ori_fmt)
1581 if self.fmt is None:
1582 return ".".join(map(str, [self.idnum for i in xrange(1+self.depth)]))
1587 oid.append(str(self.idnum))
1589 oid += map(str, [self.idnum for i in xrange(1+self.depth)])
1590 elif type(i) is tuple:
1591 oid.append(str(random.randrange(*i)))
1594 return ".".join(oid)
1598 class RandASN1Object(RandField):
1599 def __init__(self, objlist=None):
1601 objlist = map(lambda x:x._asn1_obj,
1602 filter(lambda x:hasattr(x,"_asn1_obj"), ASN1_Class_UNIVERSAL.__rdict__.values()))
1603 self.objlist = objlist
1604 self.chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
1605 def _fix(self, n=0):
1606 o = random.choice(self.objlist)
1607 if issubclass(o, ASN1_INTEGER):
1608 return o(int(random.gauss(0,1000)))
1609 elif issubclass(o, ASN1_STRING):
1610 z = int(random.expovariate(0.05)+1)
1611 return o("".join([random.choice(self.chars) for i in range(z)]))
1612 elif issubclass(o, ASN1_SEQUENCE) and (n < 10):
1613 z = int(random.expovariate(0.08)+1)
1614 return o(map(lambda x:x._fix(n+1), [self.__class__(objlist=self.objlist)]*z))
1615 return ASN1_INTEGER(int(random.gauss(0,1000)))
1617 class RandDHCPOptions(RandField):
1618 def __init__(self, size=None, rndstr=None):
1620 size = RandNumExpo(0.05)
1623 rndstr = RandBin(RandNum(0,255))
1625 self._opts = DHCPOptions.values()
1626 self._opts.remove("pad")
1627 self._opts.remove("end")
1630 for k in range(self.size):
1631 o = random.choice(self._opts)
1633 op.append((o,self.rndstr*1))
1635 op.append((o.name, o.randval()._fix()))
1639 # Automatic timestamp
1641 class AutoTime(VolatileValue):
1642 def __init__(self, base=None):
1646 self.diff = time.time()-base
1648 return time.time()-self.diff
1650 class IntAutoTime(AutoTime):
1652 return int(time.time()-self.diff)
1655 class ZuluTime(AutoTime):
1656 def __init__(self, diff=None):
1659 return time.strftime("%y%m%d%H%M%SZ",time.gmtime(time.time()+self.diff))
1662 class DelayedEval(VolatileValue):
1663 """ Exemple of usage: DelayedEval("time.time()") """
1664 def __init__(self, expr):
1667 return eval(self.expr)
1670 class IncrementalValue(VolatileValue):
1671 def __init__(self, start=0, step=1, restart=-1):
1672 self.start = self.val = start
1674 self.restart = restart
1677 if self.val == self.restart :
1678 self.val = self.start
1680 self.val += self.step
1683 def corrupt_bytes(s, p=0.01, n=None):
1684 s = array.array("B",str(s))
1688 for i in random.sample(xrange(l), n):
1689 s[i] = random.randint(0,255)
1692 def corrupt_bits(s, p=0.01, n=None):
1693 s = array.array("B",str(s))
1697 for i in random.sample(xrange(l), n):
1698 s[i/8] ^= 1 << (i%8)
1702 class CorruptedBytes(VolatileValue):
1703 def __init__(self, s, p=0.01, n=None):
1708 return corrupt_bytes(self.s, self.p, self.n)
1710 class CorruptedBits(CorruptedBytes):
1712 return corrupt_bits(self.s, self.p, self.n)
1718 class ASN1_Error(Exception):
1721 class ASN1_Encoding_Error(ASN1_Error):
1724 class ASN1_Decoding_Error(ASN1_Error):
1727 class ASN1_BadTag_Decoding_Error(ASN1_Decoding_Error):
1732 class ASN1Codec(EnumElement):
1733 def register_stem(cls, stem):
1735 def dec(cls, s, context=None):
1736 return cls._stem.dec(s, context=context)
1737 def safedec(cls, s, context=None):
1738 return cls._stem.safedec(s, context=context)
1743 class ASN1_Codecs_metaclass(Enum_metaclass):
1744 element_class = ASN1Codec
1747 __metaclass__ = ASN1_Codecs_metaclass
1758 class ASN1Tag(EnumElement):
1759 def __init__(self, key, value, context=None, codec=None):
1760 EnumElement.__init__(self, key, value)
1761 self._context = context
1765 def clone(self): # /!\ not a real deep copy. self.codec is shared
1766 return self.__class__(self._key, self._value, self._context, self._codec)
1767 def register_asn1_object(self, asn1obj):
1768 self._asn1_obj = asn1obj
1769 def asn1_object(self, val):
1770 if hasattr(self,"_asn1_obj"):
1771 return self._asn1_obj(val)
1772 raise ASN1_Error("%r does not have any assigned ASN1 object" % self)
1773 def register(self, codecnum, codec):
1774 self._codec[codecnum] = codec
1775 def get_codec(self, codec):
1777 c = self._codec[codec]
1778 except KeyError,msg:
1779 raise ASN1_Error("Codec %r not found for tag %r" % (codec, self))
1782 class ASN1_Class_metaclass(Enum_metaclass):
1783 element_class = ASN1Tag
1784 def __new__(cls, name, bases, dct): # XXX factorise a bit with Enum_metaclass.__new__()
1786 for k,v in b.__dict__.iteritems():
1787 if k not in dct and isinstance(v,ASN1Tag):
1791 for k,v in dct.iteritems():
1796 elif isinstance(v, ASN1Tag):
1798 dct["__rdict__"] = rdict
1800 cls = type.__new__(cls, name, bases, dct)
1801 for v in cls.__dict__.values():
1802 if isinstance(v, ASN1Tag):
1803 v.context = cls # overwrite ASN1Tag contexts, even cloned ones
1808 __metaclass__ = ASN1_Class_metaclass
1810 class ASN1_Class_UNIVERSAL(ASN1_Class):
1822 OBJECT_DESCRIPTOR = 7
1829 SEQUENCE = 0x30#XXX 16 ??
1830 SET = 0x31 #XXX 17 ??
1832 PRINTABLE_STRING = 19
1834 VIDEOTEX_STRING = 21
1837 GENERALIZED_TIME = 24
1841 UNIVERSAL_STRING = 28
1847 class ASN1_Object_metaclass(type):
1848 def __new__(cls, name, bases, dct):
1849 c = super(ASN1_Object_metaclass, cls).__new__(cls, name, bases, dct)
1851 c.tag.register_asn1_object(c)
1853 warning("Error registering %r for %r" % (c.tag, c.codec))
1858 __metaclass__ = ASN1_Object_metaclass
1859 tag = ASN1_Class_UNIVERSAL.ANY
1860 def __init__(self, val):
1862 def enc(self, codec):
1863 return self.tag.get_codec(codec).enc(self.val)
1865 return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), self.val)
1867 return self.enc(conf.ASN1_default_codec)
1868 def strshow(self, lvl=0):
1869 return (" "*lvl)+repr(self)+"\n"
1870 def show(self, lvl=0):
1871 print self.strshow(lvl)
1872 def __eq__(self, other):
1873 return self.val == other
1874 def __cmp__(self, other):
1875 return cmp(self.val, other)
1877 class ASN1_DECODING_ERROR(ASN1_Object):
1878 tag = ASN1_Class_UNIVERSAL.ERROR
1879 def __init__(self, val, exc=None):
1880 ASN1_Object.__init__(self, val)
1883 return "<%s[%r]{{%s}}>" % (self.__dict__.get("name", self.__class__.__name__),
1884 self.val, self.exc.args[0])
1885 def enc(self, codec):
1886 if isinstance(self.val, ASN1_Object):
1887 return self.val.enc(codec)
1890 class ASN1_force(ASN1_Object):
1891 tag = ASN1_Class_UNIVERSAL.RAW
1892 def enc(self, codec):
1893 if isinstance(self.val, ASN1_Object):
1894 return self.val.enc(codec)
1897 class ASN1_BADTAG(ASN1_force):
1900 class ASN1_INTEGER(ASN1_Object):
1901 tag = ASN1_Class_UNIVERSAL.INTEGER
1903 class ASN1_STRING(ASN1_Object):
1904 tag = ASN1_Class_UNIVERSAL.STRING
1906 class ASN1_BIT_STRING(ASN1_STRING):
1907 tag = ASN1_Class_UNIVERSAL.BIT_STRING
1909 class ASN1_PRINTABLE_STRING(ASN1_STRING):
1910 tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING
1912 class ASN1_T61_STRING(ASN1_STRING):
1913 tag = ASN1_Class_UNIVERSAL.T61_STRING
1915 class ASN1_IA5_STRING(ASN1_STRING):
1916 tag = ASN1_Class_UNIVERSAL.IA5_STRING
1918 class ASN1_NUMERIC_STRING(ASN1_STRING):
1919 tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING
1921 class ASN1_VIDEOTEX_STRING(ASN1_STRING):
1922 tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING
1924 class ASN1_UTC_TIME(ASN1_STRING):
1925 tag = ASN1_Class_UNIVERSAL.UTC_TIME
1927 class ASN1_TIME_TICKS(ASN1_INTEGER):
1928 tag = ASN1_Class_UNIVERSAL.TIME_TICKS
1930 class ASN1_BOOLEAN(ASN1_INTEGER):
1931 tag = ASN1_Class_UNIVERSAL.BOOLEAN
1933 class ASN1_NULL(ASN1_INTEGER):
1934 tag = ASN1_Class_UNIVERSAL.NULL
1936 class ASN1_COUNTER32(ASN1_INTEGER):
1937 tag = ASN1_Class_UNIVERSAL.COUNTER32
1939 class ASN1_SEQUENCE(ASN1_Object):
1940 tag = ASN1_Class_UNIVERSAL.SEQUENCE
1941 def strshow(self, lvl=0):
1942 s = (" "*lvl)+("# %s:" % self.__class__.__name__)+"\n"
1944 s += o.strshow(lvl=lvl+1)
1947 class ASN1_SET(ASN1_SEQUENCE):
1948 tag = ASN1_Class_UNIVERSAL.SET
1950 class ASN1_OID(ASN1_Object):
1951 tag = ASN1_Class_UNIVERSAL.OID
1952 def __init__(self, val):
1953 val = conf.mib._oid(val)
1954 ASN1_Object.__init__(self, val)
1956 return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), conf.mib._oidname(self.val))
1966 #####[ BER tools ]#####
1969 class BER_Exception(Exception):
1972 class BER_Decoding_Error(ASN1_Decoding_Error):
1973 def __init__(self, msg, decoded=None, remaining=None):
1974 Exception.__init__(self, msg)
1975 self.remaining = remaining
1976 self.decoded = decoded
1978 s = Exception.__str__(self)
1979 if isinstance(self.decoded, BERcodec_Object):
1980 s+="\n### Already decoded ###\n%s" % self.decoded.strshow()
1982 s+="\n### Already decoded ###\n%r" % self.decoded
1983 s+="\n### Remaining ###\n%r" % self.remaining
1986 class BER_BadTag_Decoding_Error(BER_Decoding_Error, ASN1_BadTag_Decoding_Error):
1989 def BER_len_enc(l, size=0):
1990 if l <= 127 and size==0:
1998 raise BER_Exception("BER_len_enc: Length too long (%i) to be encoded [%r]" % (len(s),s))
1999 return chr(len(s)|0x80)+s
2006 raise BER_Decoding_Error("BER_len_dec: Got %i bytes while expecting %i" % (len(s)-1, l),remaining=s)
2013 def BER_num_enc(l, size=1):
2016 x.insert(0, l & 0x7f)
2021 return "".join([chr(k) for k in x])
2024 for i in range(len(s)):
2031 raise BER_Decoding_Error("BER_num_dec: unfinished number description", remaining=s)
2034 #####[ BER classes ]#####
2036 class BERcodec_metaclass(type):
2037 def __new__(cls, name, bases, dct):
2038 c = super(BERcodec_metaclass, cls).__new__(cls, name, bases, dct)
2040 c.tag.register(c.codec, c)
2042 warning("Error registering %r for %r" % (c.tag, c.codec))
2046 class BERcodec_Object:
2047 __metaclass__ = BERcodec_metaclass
2048 codec = ASN1_Codecs.BER
2049 tag = ASN1_Class_UNIVERSAL.ANY
2052 def asn1_object(cls, val):
2053 return cls.tag.asn1_object(val)
2056 def check_string(cls, s):
2058 raise BER_Decoding_Error("%s: Got empty object while expecting tag %r" %
2059 (cls.__name__,cls.tag), remaining=s)
2061 def check_type(cls, s):
2063 if cls.tag != ord(s[0]):
2064 raise BER_BadTag_Decoding_Error("%s: Got tag [%i/%#x] while expecting %r" %
2065 (cls.__name__, ord(s[0]), ord(s[0]),cls.tag), remaining=s)
2068 def check_type_get_len(cls, s):
2069 s2 = cls.check_type(s)
2071 raise BER_Decoding_Error("%s: No bytes while expecting a length" %
2072 cls.__name__, remaining=s)
2073 return BER_len_dec(s2)
2075 def check_type_check_len(cls, s):
2076 l,s3 = cls.check_type_get_len(s)
2078 raise BER_Decoding_Error("%s: Got %i bytes while expecting %i" %
2079 (cls.__name__, len(s3), l), remaining=s)
2080 return l,s3[:l],s3[l:]
2083 def do_dec(cls, s, context=None, safe=False):
2085 context = cls.tag.context
2088 if p not in context:
2092 raise BER_Decoding_Error("Unknown prefix [%02x] for [%r]" % (p,t), remaining=s)
2093 codec = context[p].get_codec(ASN1_Codecs.BER)
2094 return codec.dec(s,context,safe)
2097 def dec(cls, s, context=None, safe=False):
2099 return cls.do_dec(s, context, safe)
2101 return cls.do_dec(s, context, safe)
2102 except BER_BadTag_Decoding_Error,e:
2103 o,remain = BERcodec_Object.dec(e.remaining, context, safe)
2104 return ASN1_BADTAG(o),remain
2105 except BER_Decoding_Error, e:
2106 return ASN1_DECODING_ERROR(s, exc=e),""
2107 except ASN1_Error, e:
2108 return ASN1_DECODING_ERROR(s, exc=e),""
2111 def safedec(cls, s, context=None):
2112 return cls.dec(s, context, safe=True)
2118 return BERcodec_STRING.enc(s)
2120 return BERcodec_INTEGER.enc(int(s))
2124 ASN1_Codecs.BER.register_stem(BERcodec_Object)
2127 class BERcodec_INTEGER(BERcodec_Object):
2128 tag = ASN1_Class_UNIVERSAL.INTEGER
2142 s.append(BER_len_enc(len(s)))
2143 s.append(chr(cls.tag))
2147 def do_dec(cls, s, context=None, safe=False):
2148 l,s,t = cls.check_type_check_len(s)
2151 if ord(s[0])&0x80: # negative int
2156 return cls.asn1_object(x),t
2159 class BERcodec_BOOLEAN(BERcodec_INTEGER):
2160 tag = ASN1_Class_UNIVERSAL.BOOLEAN
2162 class BERcodec_NULL(BERcodec_INTEGER):
2163 tag = ASN1_Class_UNIVERSAL.NULL
2167 return chr(cls.tag)+"\0"
2169 return super(cls,cls).enc(i)
2171 class BERcodec_STRING(BERcodec_Object):
2172 tag = ASN1_Class_UNIVERSAL.STRING
2175 return chr(cls.tag)+BER_len_enc(len(s))+s
2177 def do_dec(cls, s, context=None, safe=False):
2178 l,s,t = cls.check_type_check_len(s)
2179 return cls.tag.asn1_object(s),t
2181 class BERcodec_BIT_STRING(BERcodec_STRING):
2182 tag = ASN1_Class_UNIVERSAL.BIT_STRING
2184 class BERcodec_PRINTABLE_STRING(BERcodec_STRING):
2185 tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING
2187 class BERcodec_T61_STRING (BERcodec_STRING):
2188 tag = ASN1_Class_UNIVERSAL.T61_STRING
2190 class BERcodec_IA5_STRING(BERcodec_STRING):
2191 tag = ASN1_Class_UNIVERSAL.IA5_STRING
2193 class BERcodec_UTC_TIME(BERcodec_STRING):
2194 tag = ASN1_Class_UNIVERSAL.UTC_TIME
2196 class BERcodec_TIME_TICKS(BERcodec_INTEGER):
2197 tag = ASN1_Class_UNIVERSAL.TIME_TICKS
2199 class BERcodec_COUNTER32(BERcodec_INTEGER):
2200 tag = ASN1_Class_UNIVERSAL.COUNTER32
2202 class BERcodec_SEQUENCE(BERcodec_Object):
2203 tag = ASN1_Class_UNIVERSAL.SEQUENCE
2206 if type(l) is not str:
2207 l = "".join(map(lambda x: x.enc(cls.codec), l))
2208 return chr(cls.tag)+BER_len_enc(len(l))+l
2210 def do_dec(cls, s, context=None, safe=False):
2212 context = cls.tag.context
2213 l,st = cls.check_type_get_len(s) # we may have len(s) < l
2218 o,s = BERcodec_Object.dec(s, context, safe)
2219 except BER_Decoding_Error, err:
2221 if err.decoded is not None:
2222 obj.append(err.decoded)
2227 raise BER_Decoding_Error("Not enough bytes to decode sequence", decoded=obj)
2228 return cls.asn1_object(obj),t
2230 class BERcodec_SET(BERcodec_SEQUENCE):
2231 tag = ASN1_Class_UNIVERSAL.SET
2234 class BERcodec_OID(BERcodec_Object):
2235 tag = ASN1_Class_UNIVERSAL.OID
2239 lst = [int(x) for x in oid.strip(".").split(".")]
2243 s = "".join([BER_num_enc(k) for k in lst])
2244 return chr(cls.tag)+BER_len_enc(len(s))+s
2246 def do_dec(cls, s, context=None, safe=False):
2247 l,s,t = cls.check_type_check_len(s)
2250 l,s = BER_num_dec(s)
2253 lst.insert(0,lst[0]/40)
2255 return cls.asn1_object(".".join([str(k) for k in lst])), t
2262 _mib_re_integer = re.compile("^[0-9]+$")
2263 _mib_re_both = re.compile("^([a-zA-Z_][a-zA-Z0-9_-]*)\(([0-9]+)\)$")
2264 _mib_re_oiddecl = re.compile("$\s*([a-zA-Z0-9_-]+)\s+OBJECT([^:\{\}]|\{[^:]+\})+::=\s*\{([^\}]+)\}",re.M)
2265 _mib_re_strings = re.compile('"[^"]*"')
2266 _mib_re_comments = re.compile('--.*(\r|\n)')
2268 class MIBDict(DADict):
2269 def _findroot(self, x):
2270 if x.startswith("."):
2272 if not x.endswith("."):
2276 for k in self.keys():
2277 if x.startswith(self[k]+"."):
2278 if max < len(self[k]):
2281 return root, x[max:-1]
2282 def _oidname(self, x):
2283 root,remainder = self._findroot(x)
2284 return root+remainder
2286 xl = x.strip(".").split(".")
2288 while p >= 0 and _mib_re_integer.match(xl[p]):
2290 if p != 0 or xl[p] not in self:
2293 return ".".join(xl[p:])
2294 def _make_graph(self, other_keys=[], **kargs):
2295 nodes = [(k,self[k]) for k in self.keys()]
2296 oids = [self[k] for k in self.keys()]
2297 for k in other_keys:
2299 nodes.append(self.oidname(k),k)
2300 s = 'digraph "mib" {\n\trankdir=LR;\n\n'
2302 s += '\t"%s" [ label="%s" ];\n' % (o,k)
2305 parent,remainder = self._findroot(o[:-1])
2306 remainder = remainder[1:]+o[-1]
2308 parent = self[parent]
2309 s += '\t"%s" -> "%s" [label="%s"];\n' % (parent, o,remainder)
2311 do_graph(s, **kargs)
2314 def mib_register(ident, value, the_mib, unresolved):
2315 if ident in the_mib or ident in unresolved:
2316 return ident in the_mib
2320 if _mib_re_integer.match(v):
2324 if v not in the_mib:
2328 elif v in unresolved:
2335 unresolved[ident] = resval
2338 the_mib[ident] = resval
2339 keys = unresolved.keys()
2341 while i < len(keys):
2343 if mib_register(k,unresolved[k], the_mib, {}):
2353 def load_mib(filenames):
2354 the_mib = {'iso': ['1']}
2356 for k in conf.mib.keys():
2357 mib_register(k, conf.mib[k].split("."), the_mib, unresolved)
2359 if type(filenames) is str:
2360 filenames = [filenames]
2361 for fnames in filenames:
2362 for fname in glob(fnames):
2365 cleantext = " ".join(_mib_re_strings.split(" ".join(_mib_re_comments.split(text))))
2366 for m in _mib_re_oiddecl.finditer(cleantext):
2368 ident,oid = gr[0],gr[-1]
2369 ident=fixname(ident)
2371 for i in range(len(oid)):
2372 m = _mib_re_both.match(oid[i])
2374 oid[i] = m.groups()[1]
2375 mib_register(ident, oid, the_mib, unresolved)
2377 newmib = MIBDict(_name="MIB")
2378 for k,o in the_mib.iteritems():
2379 newmib[k]=".".join(o)
2380 for k,o in unresolved.iteritems():
2381 newmib[k]=".".join(o)
2396 def __init__(self, set, _iterpacket=1):
2397 self._iterpacket=_iterpacket
2398 if type(set) is list:
2400 elif isinstance(set, PacketList):
2401 self.set = list(set)
2404 def transf(self, element):
2408 if (type(i) is tuple) and (len(i) == 2) and type(i[0]) is int and type(i[1]) is int:
2414 elif isinstance(i, Gen) and (self._iterpacket or not isinstance(i,Packet)):
2420 return "<SetGen %s>" % self.set.__repr__()
2423 """Generate a list of IPs from a network address or a name"""
2425 ipaddress = re.compile(r"^(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)(/[0-3]?[0-9])?$")
2426 def __init__(self, net):
2429 tmp=net.split('/')+["32"]
2430 if not self.ipaddress.match(net):
2431 tmp[0]=socket.gethostbyname(tmp[0])
2432 netmask = int(tmp[1])
2434 def parse_digit(a,netmask):
2435 netmask = min(8,max(netmask,0))
2438 elif a.find("-") >= 0:
2439 x,y = map(int,a.split("-"))
2442 a = (x & (0xffL<<netmask) , max(y, (x | (0xffL>>(8-netmask))))+1)
2444 a = (int(a) & (0xffL<<netmask),(int(a) | (0xffL>>(8-netmask)))+1)
2447 self.parsed = map(lambda x,y: parse_digit(x,y), tmp[0].split("."), map(lambda x,nm=netmask: x-nm, (8,16,24,32)))
2450 for d in xrange(*self.parsed[3]):
2451 for c in xrange(*self.parsed[2]):
2452 for b in xrange(*self.parsed[1]):
2453 for a in xrange(*self.parsed[0]):
2454 yield "%i.%i.%i.%i" % (a,b,c,d)
2457 for v in self.parsed:
2458 ip.append(str(random.randint(v[0],v[1]-1)))
2462 return "Net(%r)" % self.repr
2466 def __init__(self, oid):
2470 for i in oid.split("."):
2473 self.cmpt.append(tuple(map(int, i.split("-"))))
2476 self.fmt = ".".join(fmt)
2478 return "OID(%r)" % self.oid
2480 ii = [k[0] for k in self.cmpt]
2482 yield self.fmt % tuple(ii)
2487 if ii[i] < self.cmpt[i][1]:
2491 ii[i] = self.cmpt[i][0]
2501 def __init__(self, res=None, name="PacketList", stats=None):
2502 """create a packet list from a list of packets
2503 res: the list of packets
2504 stats: a list of classes that will appear in the stats (defaults to [TCP,UDP,ICMP])"""
2506 stats = [ TCP,UDP,ICMP ]
2510 if isinstance(res, PacketList):
2513 self.listname = name
2514 def _elt2pkt(self, elt):
2516 def _elt2sum(self, elt):
2517 return elt.summary()
2518 def _elt2show(self, elt):
2519 return self._elt2sum(elt)
2521 # stats=dict.fromkeys(self.stats,0) ## needs python >= 2.3 :(
2522 stats = dict(map(lambda x: (x,0), self.stats))
2527 if self._elt2pkt(r).haslayer(p):
2534 ct = conf.color_theme
2535 for p in self.stats:
2536 s += " %s%s%s" % (ct.packetlist_proto(p.name),
2538 ct.packetlist_value(stats[p]))
2539 s += " %s%s%s" % (ct.packetlist_proto("Other"),
2541 ct.packetlist_value(other))
2542 return "%s%s%s%s%s" % (ct.punct("<"),
2543 ct.packetlist_name(self.listname),
2547 def __getattr__(self, attr):
2548 return getattr(self.res, attr)
2549 def __getitem__(self, item):
2550 if isinstance(item,type) and issubclass(item,Packet):
2551 return self.__class__(filter(lambda x: item in self._elt2pkt(x),self.res),
2552 name="%s from %s"%(item.__name__,self.listname))
2553 if type(item) is slice:
2554 return self.__class__(self.res.__getitem__(item),
2555 name = "mod %s" % self.listname)
2556 return self.res.__getitem__(item)
2557 def __getslice__(self, *args, **kargs):
2558 return self.__class__(self.res.__getslice__(*args, **kargs),
2559 name="mod %s"%self.listname)
2560 def __add__(self, other):
2561 return self.__class__(self.res+other.res,
2562 name="%s+%s"%(self.listname,other.listname))
2563 def summary(self, prn=None, lfilter=None):
2564 """prints a summary of each packet
2565 prn: function to apply to each packet instead of lambda x:x.summary()
2566 lfilter: truth function to apply to each packet to decide whether it will be displayed"""
2568 if lfilter is not None:
2572 print self._elt2sum(r)
2575 def nsummary(self,prn=None, lfilter=None):
2576 """prints a summary of each packet with the packet's number
2577 prn: function to apply to each packet instead of lambda x:x.summary()
2578 lfilter: truth function to apply to each packet to decide whether it will be displayed"""
2579 for i in range(len(self.res)):
2580 if lfilter is not None:
2581 if not lfilter(self.res[i]):
2583 print conf.color_theme.id(i,"%04i"),
2585 print self._elt2sum(self.res[i])
2587 print prn(self.res[i])
2588 def display(self): # Deprecated. Use show()
2589 """deprecated. is show()"""
2591 def show(self, *args, **kargs):
2592 """Best way to display the packet list. Defaults to nsummary() method"""
2593 return self.nsummary(*args, **kargs)
2595 def filter(self, func):
2596 """Returns a packet list filtered by a truth function"""
2597 return self.__class__(filter(func,self.res),
2598 name="filtered %s"%self.listname)
2599 def make_table(self, *args, **kargs):
2600 """Prints a table using a function that returs for each packet its head column value, head row value and displayed value
2601 ex: p.make_table(lambda x:(x[IP].dst, x[TCP].dport, x[TCP].sprintf("%flags%")) """
2602 return make_table(self.res, *args, **kargs)
2603 def make_lined_table(self, *args, **kargs):
2604 """Same as make_table, but print a table with lines"""
2605 return make_lined_table(self.res, *args, **kargs)
2606 def make_tex_table(self, *args, **kargs):
2607 """Same as make_table, but print a table with LaTeX syntax"""
2608 return make_tex_table(self.res, *args, **kargs)
2610 def plot(self, f, lfilter=None,**kargs):
2611 """Applies a function to each packet to get a value that will be plotted with GnuPlot. A gnuplot object is returned
2612 lfilter: a truth function that decides whether a packet must be ploted"""
2615 if lfilter is not None:
2616 l = filter(lfilter, l)
2618 g.plot(Gnuplot.Data(l, **kargs))
2621 def diffplot(self, f, delay=1, lfilter=None, **kargs):
2622 """diffplot(f, delay=1, lfilter=None)
2623 Applies a function to couples (l[i],l[i+delay])"""
2624 g = Gnuplot.Gnuplot()
2626 if lfilter is not None:
2627 l = filter(lfilter, l)
2628 l = map(f,l[:-delay],l[delay:])
2629 g.plot(Gnuplot.Data(l, **kargs))
2632 def multiplot(self, f, lfilter=None, **kargs):
2633 """Uses a function that returns a label and a value for this label, then plots all the values label by label"""
2636 if lfilter is not None:
2637 l = filter(lfilter, l)
2648 data.append(Gnuplot.Data(d[k], title=k, **kargs))
2654 def rawhexdump(self):
2655 """Prints an hexadecimal dump of each packet in the list"""
2657 hexdump(self._elt2pkt(p))
2659 def hexraw(self, lfilter=None):
2660 """Same as nsummary(), except that if a packet has a Raw layer, it will be hexdumped
2661 lfilter: a truth function that decides whether a packet must be displayed"""
2662 for i in range(len(self.res)):
2663 p = self._elt2pkt(self.res[i])
2664 if lfilter is not None and not lfilter(p):
2666 print "%s %s %s" % (conf.color_theme.id(i,"%04i"),
2667 p.sprintf("%.time%"),
2668 self._elt2sum(self.res[i]))
2670 hexdump(p.getlayer(Raw).load)
2672 def hexdump(self, lfilter=None):
2673 """Same as nsummary(), except that packets are also hexdumped
2674 lfilter: a truth function that decides whether a packet must be displayed"""
2675 for i in range(len(self.res)):
2676 p = self._elt2pkt(self.res[i])
2677 if lfilter is not None and not lfilter(p):
2679 print "%s %s %s" % (conf.color_theme.id(i,"%04i"),
2680 p.sprintf("%.time%"),
2681 self._elt2sum(self.res[i]))
2684 def padding(self, lfilter=None):
2685 """Same as hexraw(), for Padding layer"""
2686 for i in range(len(self.res)):
2687 p = self._elt2pkt(self.res[i])
2688 if p.haslayer(Padding):
2689 if lfilter is None or lfilter(p):
2690 print "%s %s %s" % (conf.color_theme.id(i,"%04i"),
2691 p.sprintf("%.time%"),
2692 self._elt2sum(self.res[i]))
2693 hexdump(p.getlayer(Padding).load)
2695 def nzpadding(self, lfilter=None):
2696 """Same as padding() but only non null padding"""
2697 for i in range(len(self.res)):
2698 p = self._elt2pkt(self.res[i])
2699 if p.haslayer(Padding):
2700 pad = p.getlayer(Padding).load
2701 if pad == pad[0]*len(pad):
2703 if lfilter is None or lfilter(p):
2704 print "%s %s %s" % (conf.color_theme.id(i,"%04i"),
2705 p.sprintf("%.time%"),
2706 self._elt2sum(self.res[i]))
2707 hexdump(p.getlayer(Padding).load)
2710 def conversations(self, getsrcdst=None,**kargs):
2711 """Graphes a conversations between sources and destinations and display it
2712 (using graphviz and imagemagick)
2713 getsrcdst: a function that takes an element of the list and return the source and dest
2714 by defaults, return source and destination IP
2715 type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option
2716 target: filename or redirect. Defaults pipe to Imagemagick's display program
2717 prog: which graphviz program to use"""
2718 if getsrcdst is None:
2719 getsrcdst = lambda x:(x[IP].src, x[IP].dst)
2722 p = self._elt2pkt(p)
2728 conv[c] = conv.get(c,0)+1
2729 gr = 'digraph "conv" {\n'
2731 gr += '\t "%s" -> "%s"\n' % (s,d)
2733 return do_graph(gr, **kargs)
2735 def afterglow(self, src=None, event=None, dst=None, **kargs):
2736 """Experimental clone attempt of http://sourceforge.net/projects/afterglow
2737 each datum is reduced as src -> event -> dst and the data are graphed.
2738 by default we have IP.src -> IP.dport -> IP.dst"""
2740 src = lambda x: x[IP].src
2742 event = lambda x: x[IP].dport
2744 dst = lambda x: x[IP].dst
2750 s,e,d = src(i),event(i),dst(i)
2767 dl[d] = dl.get(d,0)+1
2773 return 2+math.log(n)/4.0
2783 mins,maxs = minmax(map(lambda (x,y): x, sl.values()))
2784 mine,maxe = minmax(map(lambda (x,y): x, el.values()))
2785 mind,maxd = minmax(dl.values())
2787 gr = 'digraph "afterglow" {\n\tedge [len=2.5];\n'
2789 gr += "# src nodes\n"
2791 n,l = sl[s]; n = 1+float(n-mins)/(maxs-mins)
2792 gr += '"src.%s" [label = "%s", shape=box, fillcolor="#FF0000", style=filled, fixedsize=1, height=%.2f,width=%.2f];\n' % (`s`,`s`,n,n)
2793 gr += "# event nodes\n"
2795 n,l = el[e]; n = n = 1+float(n-mine)/(maxe-mine)
2796 gr += '"evt.%s" [label = "%s", shape=circle, fillcolor="#00FFFF", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`e`,`e`,n,n)
2798 n = dl[d]; n = n = 1+float(n-mind)/(maxd-mind)
2799 gr += '"dst.%s" [label = "%s", shape=triangle, fillcolor="#0000ff", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`d`,`d`,n,n)
2805 gr += ' "src.%s" -> "evt.%s";\n' % (`s`,`e`)
2809 gr += ' "evt.%s" -> "dst.%s";\n' % (`e`,`d`)
2812 open("/tmp/aze","w").write(gr)
2813 return do_graph(gr, **kargs)
2817 def timeskew_graph(self, ip, **kargs):
2818 """Tries to graph the timeskew between the timestamps and real time for a given ip"""
2819 res = map(lambda x: self._elt2pkt(x), self.res)
2820 b = filter(lambda x:x.haslayer(IP) and x.getlayer(IP).src == ip and x.haslayer(TCP), res)
2823 opts = p.getlayer(TCP).options
2825 if o[0] == "Timestamp":
2826 c.append((p.time,o[1][0]))
2828 warning("No timestamps found in packet list")
2830 d = map(lambda (x,y): (x%2000,((x-c[0][0])-((y-c[0][1])/1000.0))),c)
2831 g = Gnuplot.Gnuplot()
2832 g.plot(Gnuplot.Data(d,**kargs))
2835 def _dump_document(self, **kargs):
2836 d = pyx.document.document()
2838 for i in range(len(self.res)):
2840 c = self._elt2pkt(elt).canvas_dump(**kargs)
2842 c.text(cbb.left(),cbb.top()+1,r"\font\cmssfont=cmss12\cmssfont{Frame %i/%i}" % (i,l),[pyx.text.size.LARGE])
2845 d.append(pyx.document.page(c, paperformat=pyx.document.paperformat.A4,
2846 margin=1*pyx.unit.t_cm,
2852 def psdump(self, filename = None, **kargs):
2853 """Creates a multipage poscript file with a psdump of every packet
2854 filename: name of the file to write to. If empty, a temporary file is used and
2855 conf.prog.psreader is called"""
2856 d = self._dump_document(**kargs)
2857 if filename is None:
2858 filename = "/tmp/scapy.psd.%i" % os.getpid()
2859 d.writePSfile(filename)
2860 os.system("%s %s.ps &" % (conf.prog.psreader,filename))
2862 d.writePSfile(filename)
2865 def pdfdump(self, filename = None, **kargs):
2866 """Creates a PDF file with a psdump of every packet
2867 filename: name of the file to write to. If empty, a temporary file is used and
2868 conf.prog.pdfreader is called"""
2869 d = self._dump_document(**kargs)
2870 if filename is None:
2871 filename = "/tmp/scapy.psd.%i" % os.getpid()
2872 d.writePDFfile(filename)
2873 os.system("%s %s.pdf &" % (conf.prog.pdfreader,filename))
2875 d.writePDFfile(filename)
2878 def sr(self,multi=0):
2879 """sr([multi=1]) -> (SndRcvList, PacketList)
2880 Matches packets in the list and return ( (matched couples), (unmatched packets) )"""
2881 remain = self.res[:]
2884 while i < len(remain):
2887 while j < len(remain)-1:
2893 remain[i]._answered=1
2894 remain[j]._answered=2
2902 remain = filter(lambda x:not hasattr(x,"_answered"), remain)
2903 return SndRcvList(sr),PacketList(remain)
2910 class Dot11PacketList(PacketList):
2911 def __init__(self, res=None, name="Dot11List", stats=None):
2913 stats = [Dot11WEP, Dot11Beacon, UDP, ICMP, TCP]
2915 PacketList.__init__(self, res, name, stats)
2916 def toEthernet(self):
2917 data = map(lambda x:x.getlayer(Dot11), filter(lambda x : x.haslayer(Dot11) and x.type == 2, self.res))
2922 r2.append(Ether()/q.payload.payload.payload) #Dot11/LLC/SNAP/IP
2923 return PacketList(r2,name="Ether from %s"%self.listname)
2927 class SndRcvList(PacketList):
2928 def __init__(self, res=None, name="Results", stats=None):
2929 PacketList.__init__(self, res, name, stats)
2930 def _elt2pkt(self, elt):
2932 def _elt2sum(self, elt):
2933 return "%s ==> %s" % (elt[0].summary(),elt[1].summary())
2936 class ARPingResult(SndRcvList):
2937 def __init__(self, res=None, name="ARPing", stats=None):
2938 PacketList.__init__(self, res, name, stats)
2941 for s,r in self.res:
2942 print r.sprintf("%Ether.src% %ARP.psrc%")
2948 def __init__(self, server=None, port=43, options=None):
2949 if server is not None:
2950 self.server = server
2952 if options is not None:
2953 self.options = options
2956 self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2957 self.s.connect((self.server,self.port))
2959 self.s.send(self.options+"\n")
2964 def _parse_whois(self, txt):
2966 for l in txt.splitlines():
2967 if not asn and l.startswith("origin:"):
2969 if l.startswith("descr:"):
2972 desc += l[6:].strip()
2973 if asn is not None and desc:
2975 return asn,desc.strip()
2977 def _resolve_one(self, ip):
2978 self.s.send("%s\n" % ip)
2980 while not ("%" in x or "source" in x):
2981 x += self.s.recv(8192)
2982 asn, desc = self._parse_whois(x)
2984 def resolve(self, *ips):
2988 ip,asn,desc = self._resolve_one(ip)
2990 ret.append((ip,asn,desc))
2994 class AS_resolver_riswhois(AS_resolver):
2995 server = "riswhois.ripe.net"
2996 options = "-k -M -1"
2999 class AS_resolver_radb(AS_resolver):
3000 server = "whois.ra.net"
3004 class AS_resolver_cymru(AS_resolver):
3005 server = "whois.cymru.com"
3007 def resolve(self, *ips):
3009 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
3010 s.connect((self.server,self.port))
3011 s.send("begin\r\n"+"\r\n".join(ips)+"\r\nend\r\n")
3019 for l in r.splitlines()[1:]:
3022 asn,ip,desc = map(str.strip, l.split("|"))
3026 ASNlist.append((ip,asn,desc))
3029 class AS_resolver_multi(AS_resolver):
3030 resolvers_list = ( AS_resolver_cymru(),AS_resolver_riswhois(),AS_resolver_radb() )
3031 def __init__(self, *reslist):
3033 self.resolvers_list = reslist
3034 def resolve(self, *ips):
3037 for ASres in self.resolvers_list:
3038 res = ASres.resolve(*todo)
3039 resolved = [ ip for ip,asn,desc in res ]
3040 todo = [ ip for ip in todo if ip not in resolved ]
3046 class TracerouteResult(SndRcvList):
3047 def __init__(self, res=None, name="Traceroute", stats=None):
3048 PacketList.__init__(self, res, name, stats)
3049 self.graphdef = None
3056 return self.make_table(lambda (s,r): (s.sprintf("%IP.dst%:{TCP:tcp%ir,TCP.dport%}{UDP:udp%ir,UDP.dport%}{ICMP:ICMP}"),
3058 r.sprintf("%-15s,IP.src% {TCP:%TCP.flags%}{ICMP:%ir,ICMP.type%}")))
3061 def get_trace(self):
3063 for s,r in self.res:
3069 trace[d][s[IP].ttl] = r[IP].src, ICMP not in r
3070 for k in trace.values():
3071 m = filter(lambda x:k[x][1], k.keys())
3081 """Give a 3D representation of the traceroute.
3082 right button: rotate the scene
3084 left button: move the scene
3085 left button on a ball: toggle IP displaying
3086 ctrl-left button on a ball: scan ports 21,22,23,25,80 and 443 and display the result"""
3087 trace = self.get_trace()
3090 class IPsphere(visual.sphere):
3091 def __init__(self, ip, **kargs):
3092 visual.sphere.__init__(self, **kargs)
3095 self.setlabel(self.ip)
3096 def setlabel(self, txt,visible=None):
3097 if self.label is not None:
3099 visible = self.label.visible
3100 self.label.visible = 0
3101 elif visible is None:
3103 self.label=visual.label(text=txt, pos=self.pos, space=self.radius, xoffset=10, yoffset=20, visible=visible)
3105 self.label.visible ^= 1
3107 visual.scene = visual.display()
3108 visual.scene.exit_on_close(0)
3109 start = visual.box()
3116 for t in range(1,max(ttl)+1):
3120 if tr[t] not in rings[t]:
3121 rings[t].append(tr[t])
3122 tr3d[i].append(rings[t].index(tr[t]))
3124 rings[t].append(("unk",-1))
3125 tr3d[i].append(len(rings[t])-1)
3131 col = (0.75,0.75,0.75)
3133 col = visual.color.green
3135 col = visual.color.blue
3137 s = IPsphere(pos=((l-1)*visual.cos(2*i*visual.pi/l),(l-1)*visual.sin(2*i*visual.pi/l),2*t),
3140 for trlst in tr3d.values():
3144 forecol = colgen(0.625, 0.4375, 0.25, 0.125)
3145 for trlst in tr3d.values():
3146 col = forecol.next()
3149 visual.cylinder(pos=start,axis=ip.pos-start,color=col,radius=0.2)
3154 if visual.scene.kb.keys:
3155 k = visual.scene.kb.getkey()
3158 if visual.scene.mouse.events:
3159 ev = visual.scene.mouse.getevent()
3160 if ev.press == "left":
3168 a,b=sr(IP(dst=o.ip)/TCP(dport=[21,22,23,25,80,443]),timeout=2)
3171 txt = "%s:\nno results" % o.ip
3173 txt = "%s:\n" % o.ip
3175 txt += r.sprintf("{TCP:%IP.src%:%TCP.sport% %TCP.flags%}{TCPerror:%IPerror.dst%:%TCPerror.dport% %IP.src% %ir,ICMP.type%}\n")
3176 o.setlabel(txt, visible=1)
3178 if hasattr(o, "action"):
3180 elif ev.drag == "left":
3182 elif ev.drop == "left":
3185 visual.scene.center -= visual.scene.mouse.pos-movcenter
3186 movcenter = visual.scene.mouse.pos
3189 def world_trace(self):
3193 for s,r in self.res:
3195 if s.haslayer(TCP) or s.haslayer(UDP):
3196 trace_id = (s.src,s.dst,s.proto,s.dport)
3197 elif s.haslayer(ICMP):
3198 trace_id = (s.src,s.dst,s.proto,s.type)
3200 trace_id = (s.src,s.dst,s.proto,0)
3201 trace = rt.get(trace_id,{})
3202 if not r.haslayer(ICMP) or r.type != 11:
3203 if ports_done.has_key(trace_id):
3205 ports_done[trace_id] = None
3206 trace[s.ttl] = r.src
3207 rt[trace_id] = trace
3211 trace = rt[trace_id]
3213 for i in range(max(trace.keys())):
3214 ip = trace.get(i,None)
3220 # loctrace.append((ip,loc)) # no labels yet
3221 loctrace.append(loc)
3223 trt[trace_id] = loctrace
3225 tr = map(lambda x: Gnuplot.Data(x,with="lines"), trt.values())
3226 g = Gnuplot.Gnuplot()
3227 world = Gnuplot.File(conf.gnuplot_world,with="lines")
3231 def make_graph(self,ASres=None,padding=0):
3233 ASres = conf.AS_resolver
3234 self.graphASres = ASres
3235 self.graphpadding = padding
3240 for s,r in self.res:
3241 r = r[IP] or r[IPv6] or r
3242 s = s[IP] or s[IPv6] or s
3245 trace_id = (s.src,s.dst,6,s.dport)
3247 trace_id = (s.src,s.dst,17,s.dport)
3249 trace_id = (s.src,s.dst,1,s.type)
3251 trace_id = (s.src,s.dst,s.proto,0)
3252 trace = rt.get(trace_id,{})
3253 ttl = IPv6 in s and s.hlim or s.ttl
3254 if not (ICMP in r and r[ICMP].type == 11) and not (IPv6 in r and ICMPv6TimeExceeded in r):
3255 if trace_id in ports_done:
3257 ports_done[trace_id] = None
3258 p = ports.get(r.src,[])
3260 p.append(r.sprintf("<T%ir,TCP.sport%> %TCP.sport% %TCP.flags%"))
3261 trace[ttl] = r.sprintf('"%r,src%":T%ir,TCP.sport%')
3263 p.append(r.sprintf("<U%ir,UDP.sport%> %UDP.sport%"))
3264 trace[ttl] = r.sprintf('"%r,src%":U%ir,UDP.sport%')
3266 p.append(r.sprintf("<I%ir,ICMP.type%> ICMP %ICMP.type%"))
3267 trace[ttl] = r.sprintf('"%r,src%":I%ir,ICMP.type%')
3269 p.append(r.sprintf("{IP:<P%ir,proto%> IP %proto%}{IPv6:<P%ir,nh%> IPv6 %nh%}"))
3270 trace[ttl] = r.sprintf('"%r,src%":{IP:P%ir,proto%}{IPv6:P%ir,nh%}')
3273 trace[ttl] = r.sprintf('"%r,src%"')
3274 rt[trace_id] = trace
3276 # Fill holes with unk%i nodes
3277 unknown_label = incremental_label("unk%i")
3283 for n in range(min(k), max(k)):
3284 if not trace.has_key(n):
3285 trace[n] = unknown_label.next()
3286 if not ports_done.has_key(rtk):
3287 if rtk[2] == 1: #ICMP
3288 bh = "%s %i/icmp" % (rtk[1],rtk[3])
3289 elif rtk[2] == 6: #TCP
3290 bh = "%s %i/tcp" % (rtk[1],rtk[3])
3291 elif rtk[2] == 17: #UDP
3292 bh = '%s %i/udp' % (rtk[1],rtk[3])
3294 bh = '%s %i/proto' % (rtk[1],rtk[2])
3298 trace[max(k)+1] = bh
3299 blackholes.append(bh)
3302 ASN_query_list = dict.fromkeys(map(lambda x:x.rsplit(" ",1)[0],ips)).keys()
3306 ASNlist = ASres.resolve(*ASN_query_list)
3310 for ip,asn,desc, in ASNlist:
3313 iplist = ASNs.get(asn,[])
3317 iplist.append(bhip[ip])