13e4ead4b7b6d9ae5ac4b4cf4c1333a116f8a2d15Phil## This file is part of Scapy
23e4ead4b7b6d9ae5ac4b4cf4c1333a116f8a2d15Phil## See http://www.secdev.org/projects/scapy for more informations
33e4ead4b7b6d9ae5ac4b4cf4c1333a116f8a2d15Phil## Copyright (C) Philippe Biondi <phil@secdev.org>
43e4ead4b7b6d9ae5ac4b4cf4c1333a116f8a2d15Phil## This program is published under a GPLv2 license
53e4ead4b7b6d9ae5ac4b4cf4c1333a116f8a2d15Phil
60ce149b41a10223c75f33a135d0a7ddc6bd2e022Dirk Loss"""
70ce149b41a10223c75f33a135d0a7ddc6bd2e022Dirk LossPacketList: holds several packets and allows to do operations on them.
80ce149b41a10223c75f33a135d0a7ddc6bd2e022Dirk Loss"""
90ce149b41a10223c75f33a135d0a7ddc6bd2e022Dirk Loss
100ce149b41a10223c75f33a135d0a7ddc6bd2e022Dirk Loss
1122a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotterfrom __future__ import absolute_import
12b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotterfrom __future__ import print_function
1360f945fd1bc6b8d4ef561d1eb17c327ecc3c954bDirk Lossimport os,subprocess
14f13602150438b4afd00a46f1dafb4062369cc835Philfrom collections import defaultdict
15bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
166057906368d55634d11e1d19a5cca1f127595b11Robin Jarryfrom scapy.config import conf
176057906368d55634d11e1d19a5cca1f127595b11Robin Jarryfrom scapy.base_classes import BasePacket,BasePacketList
186057906368d55634d11e1d19a5cca1f127595b11Robin Jarryfrom scapy.utils import do_graph,hexdump,make_table,make_lined_table,make_tex_table,get_temp_file
19e02f12feef2f5bf68e1632f01ef3ab6192d35bbbPhil
20431b04a95da67282a59bdf0a1898e106b18814d0gpotterfrom scapy.consts import plt, MATPLOTLIB_INLINED, MATPLOTLIB_DEFAULT_PLOT_KARGS
21d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotterfrom functools import reduce
2222a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotterimport scapy.modules.six as six
2322a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotterfrom scapy.modules.six.moves import filter, range, zip
245c6b1ce778d0462812fb3be4f5689682f9431a8ePhil
255c6b1ce778d0462812fb3be4f5689682f9431a8ePhil
26bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil#############
27bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil## Results ##
28bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil#############
29bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
3033c3b1a112faf0f223cf0d983aac85b95ff2c248Philclass PacketList(BasePacketList):
31aefe6fcbe454cd014487523c5470d933fa70e95cPierre LALET    __slots__ = ["stats", "res", "listname"]
32bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def __init__(self, res=None, name="PacketList", stats=None):
33bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """create a packet list from a list of packets
34bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil           res: the list of packets
35bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil           stats: a list of classes that will appear in the stats (defaults to [TCP,UDP,ICMP])"""
36bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        if stats is None:
37e02f12feef2f5bf68e1632f01ef3ab6192d35bbbPhil            stats = conf.stats_classic_protocols
38bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        self.stats = stats
39bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        if res is None:
40bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            res = []
41f53402a82b096ef1224460412790dba0daf8c60aPierre LALET        elif isinstance(res, PacketList):
42bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            res = res.res
43bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        self.res = res
44bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        self.listname = name
45bed0f3587db8b886d3c09cd9529eacf23b84590cPierre LALET    def __len__(self):
46bed0f3587db8b886d3c09cd9529eacf23b84590cPierre LALET        return len(self.res)
47bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def _elt2pkt(self, elt):
48bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return elt
49bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def _elt2sum(self, elt):
50bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return elt.summary()
51bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def _elt2show(self, elt):
52bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return self._elt2sum(elt)
53bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def __repr__(self):
54b2a7a54a35112117fd642b7f9e75ca43857a0cb9Pierre LALET        stats = {x: 0 for x in self.stats}
55bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        other = 0
56bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        for r in self.res:
57bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            f = 0
58bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            for p in stats:
59bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                if self._elt2pkt(r).haslayer(p):
60bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    stats[p] += 1
61bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    f = 1
62bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    break
63bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            if not f:
64bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                other += 1
65bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        s = ""
66bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        ct = conf.color_theme
67bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        for p in self.stats:
6806627eecaccb736e24ec155e1dcf3700acb25a0cPierre LALET            s += " %s%s%s" % (ct.packetlist_proto(p._name),
69bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                              ct.punct(":"),
70bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                              ct.packetlist_value(stats[p]))
71bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        s += " %s%s%s" % (ct.packetlist_proto("Other"),
72bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                          ct.punct(":"),
73bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                          ct.packetlist_value(other))
74bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return "%s%s%s%s%s" % (ct.punct("<"),
75bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                               ct.packetlist_name(self.listname),
76bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                               ct.punct(":"),
77bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                               s,
78bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                               ct.punct(">"))
79bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def __getattr__(self, attr):
80bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return getattr(self.res, attr)
81bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def __getitem__(self, item):
8233c3b1a112faf0f223cf0d983aac85b95ff2c248Phil        if isinstance(item,type) and issubclass(item,BasePacket):
8352165d0dd55a1071b935d002a41a95210c97f8e7Guillaume Valadon            return self.__class__([x for x in self.res if item in self._elt2pkt(x)],
84bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                                  name="%s from %s"%(item.__name__,self.listname))
85d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotter        if isinstance(item, slice):
86bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            return self.__class__(self.res.__getitem__(item),
87bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                                  name = "mod %s" % self.listname)
88bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return self.res.__getitem__(item)
89bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def __getslice__(self, *args, **kargs):
90bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return self.__class__(self.res.__getslice__(*args, **kargs),
91bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                              name="mod %s"%self.listname)
92bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def __add__(self, other):
93bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return self.__class__(self.res+other.res,
94bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                              name="%s+%s"%(self.listname,other.listname))
95bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def summary(self, prn=None, lfilter=None):
96bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """prints a summary of each packet
97bb2ddd8ef0416706e645595b6b5484ee4f409ad3Philprn:     function to apply to each packet instead of lambda x:x.summary()
98bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phillfilter: truth function to apply to each packet to decide whether it will be displayed"""
99bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        for r in self.res:
100bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            if lfilter is not None:
101bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                if not lfilter(r):
102bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    continue
103bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            if prn is None:
104b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter                print(self._elt2sum(r))
105bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            else:
106b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter                print(prn(r))
1074cca8708a5fdc52e592aa2661ab7c4b06fd539b3Pierre LALET    def nsummary(self, prn=None, lfilter=None):
108bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """prints a summary of each packet with the packet's number
109bb2ddd8ef0416706e645595b6b5484ee4f409ad3Philprn:     function to apply to each packet instead of lambda x:x.summary()
110bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phillfilter: truth function to apply to each packet to decide whether it will be displayed"""
1114cca8708a5fdc52e592aa2661ab7c4b06fd539b3Pierre LALET        for i, res in enumerate(self.res):
112bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            if lfilter is not None:
1134cca8708a5fdc52e592aa2661ab7c4b06fd539b3Pierre LALET                if not lfilter(res):
114bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    continue
115b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter            print(conf.color_theme.id(i,fmt="%04i"), end=' ')
116bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            if prn is None:
117b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter                print(self._elt2sum(res))
118bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            else:
119b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter                print(prn(res))
120bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def display(self): # Deprecated. Use show()
121bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """deprecated. is show()"""
122bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        self.show()
123bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def show(self, *args, **kargs):
124bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Best way to display the packet list. Defaults to nsummary() method"""
125bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return self.nsummary(*args, **kargs)
126bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
127bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def filter(self, func):
128bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Returns a packet list filtered by a truth function"""
12952165d0dd55a1071b935d002a41a95210c97f8e7Guillaume Valadon        return self.__class__([x for x in self.res if func(x)],
130bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                              name="filtered %s"%self.listname)
131bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def make_table(self, *args, **kargs):
132ed95a6a3cea25583d339e564b7c93bdbcbbf9483Guillaume Valadon        """Prints a table using a function that returns for each packet its head column value, head row value and displayed value
133bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        ex: p.make_table(lambda x:(x[IP].dst, x[TCP].dport, x[TCP].sprintf("%flags%")) """
134bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return make_table(self.res, *args, **kargs)
135bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def make_lined_table(self, *args, **kargs):
136bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Same as make_table, but print a table with lines"""
137bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return make_lined_table(self.res, *args, **kargs)
138bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def make_tex_table(self, *args, **kargs):
139bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Same as make_table, but print a table with LaTeX syntax"""
140bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return make_tex_table(self.res, *args, **kargs)
141bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
142f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET    def plot(self, f, lfilter=None, plot_xy=False, **kargs):
1439cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        """Applies a function to each packet to get a value that will be plotted
14469eb6679cac0ede212f8e6204227136e30d785d5Guillaume Valadon        with matplotlib. A list of matplotlib.lines.Line2D is returned.
14569eb6679cac0ede212f8e6204227136e30d785d5Guillaume Valadon
146ed95a6a3cea25583d339e564b7c93bdbcbbf9483Guillaume Valadon        lfilter: a truth function that decides whether a packet must be plotted
14769eb6679cac0ede212f8e6204227136e30d785d5Guillaume Valadon        """
14869eb6679cac0ede212f8e6204227136e30d785d5Guillaume Valadon
14969eb6679cac0ede212f8e6204227136e30d785d5Guillaume Valadon        # Get the list of packets
150f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET        if lfilter is None:
151f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET            l = [f(e) for e in self.res]
152f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET        else:
153f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET            l = [f(e) for e in self.res if lfilter(e)]
1549cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon
1559cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        # Mimic the default gnuplot output
1569cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        if kargs == {}:
1579cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon            kargs = MATPLOTLIB_DEFAULT_PLOT_KARGS
158f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET        if plot_xy:
159f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET            lines = plt.plot(*zip(*l), **kargs)
160f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET        else:
161f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET            lines = plt.plot(l, **kargs)
1629cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon
1639cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        # Call show() if matplotlib is not inlined
1649cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        if not MATPLOTLIB_INLINED:
1659cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon            plt.show()
1669cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon
1679cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        return lines
168bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
169bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def diffplot(self, f, delay=1, lfilter=None, **kargs):
170bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """diffplot(f, delay=1, lfilter=None)
17169eb6679cac0ede212f8e6204227136e30d785d5Guillaume Valadon        Applies a function to couples (l[i],l[i+delay])
17269eb6679cac0ede212f8e6204227136e30d785d5Guillaume Valadon
17369eb6679cac0ede212f8e6204227136e30d785d5Guillaume Valadon        A list of matplotlib.lines.Line2D is returned.
17469eb6679cac0ede212f8e6204227136e30d785d5Guillaume Valadon        """
17569eb6679cac0ede212f8e6204227136e30d785d5Guillaume Valadon
17669eb6679cac0ede212f8e6204227136e30d785d5Guillaume Valadon        # Get the list of packets
1772d349c190ac3e65b130e0e123b018221fd2ff7d9Guillaume Valadon        if lfilter is None:
1782d349c190ac3e65b130e0e123b018221fd2ff7d9Guillaume Valadon            l = [f(self.res[i], self.res[i+1])
17922a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotter                    for i in range(len(self.res) - delay)]
1802d349c190ac3e65b130e0e123b018221fd2ff7d9Guillaume Valadon        else:
1812d349c190ac3e65b130e0e123b018221fd2ff7d9Guillaume Valadon            l = [f(self.res[i], self.res[i+1])
18222a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotter                    for i in range(len(self.res) - delay)
1832d349c190ac3e65b130e0e123b018221fd2ff7d9Guillaume Valadon                        if lfilter(self.res[i])]
1849cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon
1859cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        # Mimic the default gnuplot output
1869cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        if kargs == {}:
1879cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon            kargs = MATPLOTLIB_DEFAULT_PLOT_KARGS
1889cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        lines = plt.plot(l, **kargs)
1899cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon
1909cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        # Call show() if matplotlib is not inlined
1919cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        if not MATPLOTLIB_INLINED:
1929cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon            plt.show()
1939cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon
1949cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        return lines
195bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
196f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET    def multiplot(self, f, lfilter=None, plot_xy=False, **kargs):
197c38efa07ef66290c38b1ff100e41995e243bec20Guillaume Valadon        """Uses a function that returns a label and a value for this label, then
198c38efa07ef66290c38b1ff100e41995e243bec20Guillaume Valadon        plots all the values label by label.
199c38efa07ef66290c38b1ff100e41995e243bec20Guillaume Valadon
200c38efa07ef66290c38b1ff100e41995e243bec20Guillaume Valadon        A list of matplotlib.lines.Line2D is returned.
201c38efa07ef66290c38b1ff100e41995e243bec20Guillaume Valadon        """
202c38efa07ef66290c38b1ff100e41995e243bec20Guillaume Valadon
203c38efa07ef66290c38b1ff100e41995e243bec20Guillaume Valadon        # Get the list of packets
204f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET        if lfilter is None:
205f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET            l = (f(e) for e in self.res)
206f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET        else:
207f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET            l = (f(e) for e in self.res if lfilter(e))
208bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
209c38efa07ef66290c38b1ff100e41995e243bec20Guillaume Valadon        # Apply the function f to the packets
210f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET        d = {}
211f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET        for k, v in l:
212f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET            d.setdefault(k, []).append(v)
213c38efa07ef66290c38b1ff100e41995e243bec20Guillaume Valadon
214c38efa07ef66290c38b1ff100e41995e243bec20Guillaume Valadon        # Mimic the default gnuplot output
215f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET        if not kargs:
216c38efa07ef66290c38b1ff100e41995e243bec20Guillaume Valadon            kargs = MATPLOTLIB_DEFAULT_PLOT_KARGS
2179cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon
218f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET        if plot_xy:
219f3a4c64e3cb35bcc55b9282cf04c79bbd07942d4Pierre LALET            lines = [plt.plot(*zip(*pl), **dict(kargs, label=k))
22022a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotter                     for k, pl in six.iteritems(d)]
221f50242c428cc6780a2637ab0482c5c63af42a1daPierre LALET        else:
222f3a4c64e3cb35bcc55b9282cf04c79bbd07942d4Pierre LALET            lines = [plt.plot(pl, **dict(kargs, label=k))
22322a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotter                     for k, pl in six.iteritems(d)]
2249cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        plt.legend(loc="center right", bbox_to_anchor=(1.5, 0.5))
2259cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon
2269cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        # Call show() if matplotlib is not inlined
2279cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        if not MATPLOTLIB_INLINED:
2289cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon            plt.show()
229bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
2309cb4a70de3c57dd3779a0aa87ea25914ac6ef98dGuillaume Valadon        return lines
231bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
232bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def rawhexdump(self):
233bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Prints an hexadecimal dump of each packet in the list"""
234bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        for p in self:
235bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            hexdump(self._elt2pkt(p))
236bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
237bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def hexraw(self, lfilter=None):
238bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Same as nsummary(), except that if a packet has a Raw layer, it will be hexdumped
239bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        lfilter: a truth function that decides whether a packet must be displayed"""
2404cca8708a5fdc52e592aa2661ab7c4b06fd539b3Pierre LALET        for i, res in enumerate(self.res):
2414cca8708a5fdc52e592aa2661ab7c4b06fd539b3Pierre LALET            p = self._elt2pkt(res)
242bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            if lfilter is not None and not lfilter(p):
243bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                continue
244b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter            print("%s %s %s" % (conf.color_theme.id(i,fmt="%04i"),
245bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                                p.sprintf("%.time%"),
246b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter                                self._elt2sum(res)))
2475f56932f2ba2726f17ec7095b460e5dfafe53199Phil            if p.haslayer(conf.raw_layer):
2485f56932f2ba2726f17ec7095b460e5dfafe53199Phil                hexdump(p.getlayer(conf.raw_layer).load)
249bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
250bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def hexdump(self, lfilter=None):
251bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Same as nsummary(), except that packets are also hexdumped
252bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        lfilter: a truth function that decides whether a packet must be displayed"""
2534cca8708a5fdc52e592aa2661ab7c4b06fd539b3Pierre LALET        for i, res in enumerate(self.res):
2544cca8708a5fdc52e592aa2661ab7c4b06fd539b3Pierre LALET            p = self._elt2pkt(res)
255bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            if lfilter is not None and not lfilter(p):
256bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                continue
257b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter            print("%s %s %s" % (conf.color_theme.id(i,fmt="%04i"),
258bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                                p.sprintf("%.time%"),
259b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter                                self._elt2sum(res)))
260bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            hexdump(p)
261bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
262bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def padding(self, lfilter=None):
263bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Same as hexraw(), for Padding layer"""
264f53402a82b096ef1224460412790dba0daf8c60aPierre LALET        for i, res in enumerate(self.res):
2654cca8708a5fdc52e592aa2661ab7c4b06fd539b3Pierre LALET            p = self._elt2pkt(res)
266eec79622b3fafb8e713a93a061a8be0de0691282Phil            if p.haslayer(conf.padding_layer):
267bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                if lfilter is None or lfilter(p):
268b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter                    print("%s %s %s" % (conf.color_theme.id(i,fmt="%04i"),
269bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                                        p.sprintf("%.time%"),
270b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter                                        self._elt2sum(res)))
271eec79622b3fafb8e713a93a061a8be0de0691282Phil                    hexdump(p.getlayer(conf.padding_layer).load)
272bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
273bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def nzpadding(self, lfilter=None):
274bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Same as padding() but only non null padding"""
275f53402a82b096ef1224460412790dba0daf8c60aPierre LALET        for i, res in enumerate(self.res):
2764cca8708a5fdc52e592aa2661ab7c4b06fd539b3Pierre LALET            p = self._elt2pkt(res)
277eec79622b3fafb8e713a93a061a8be0de0691282Phil            if p.haslayer(conf.padding_layer):
278eec79622b3fafb8e713a93a061a8be0de0691282Phil                pad = p.getlayer(conf.padding_layer).load
279bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                if pad == pad[0]*len(pad):
280bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    continue
281bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                if lfilter is None or lfilter(p):
282b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter                    print("%s %s %s" % (conf.color_theme.id(i,fmt="%04i"),
283bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                                        p.sprintf("%.time%"),
284b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter                                        self._elt2sum(res)))
285eec79622b3fafb8e713a93a061a8be0de0691282Phil                    hexdump(p.getlayer(conf.padding_layer).load)
286bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
287bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
288bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def conversations(self, getsrcdst=None,**kargs):
289bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Graphes a conversations between sources and destinations and display it
290bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        (using graphviz and imagemagick)
29198d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet        getsrcdst: a function that takes an element of the list and
29298d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                   returns the source, the destination and optionally
29398d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                   a label. By default, returns the IP source and
29498d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                   destination from IP and ARP layers
295bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option
296bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        target: filename or redirect. Defaults pipe to Imagemagick's display program
297bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        prog: which graphviz program to use"""
298bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        if getsrcdst is None:
29998d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet            def getsrcdst(pkt):
3006057906368d55634d11e1d19a5cca1f127595b11Robin Jarry                if 'IP' in pkt:
3016057906368d55634d11e1d19a5cca1f127595b11Robin Jarry                    return (pkt['IP'].src, pkt['IP'].dst)
3026057906368d55634d11e1d19a5cca1f127595b11Robin Jarry                if 'ARP' in pkt:
3036057906368d55634d11e1d19a5cca1f127595b11Robin Jarry                    return (pkt['ARP'].psrc, pkt['ARP'].pdst)
30498d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                raise TypeError()
305bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        conv = {}
306bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        for p in self.res:
307bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            p = self._elt2pkt(p)
308bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            try:
309bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                c = getsrcdst(p)
310bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            except:
31198d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                # No warning here: it's OK that getsrcdst() raises an
31298d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                # exception, since it might be, for example, a
31398d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                # function that expects a specific layer in each
31498d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                # packet. The try/except approach is faster and
31598d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                # considered more Pythonic than adding tests.
316bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                continue
31798d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet            if len(c) == 3:
31898d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                conv.setdefault(c[:2], set()).add(c[2])
31998d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet            else:
32098d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                conv[c] = conv.get(c, 0) + 1
321bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        gr = 'digraph "conv" {\n'
32222a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotter        for (s, d), l in six.iteritems(conv):
32398d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet            gr += '\t "%s" -> "%s" [label="%s"]\n' % (
32498d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet                s, d, ', '.join(str(x) for x in l) if isinstance(l, set) else l
32598d3ff422570ae47c2f19f7d8115431e0e2b6ed3Pierre Lalet            )
326bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        gr += "}\n"
327bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return do_graph(gr, **kargs)
328bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
329bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def afterglow(self, src=None, event=None, dst=None, **kargs):
330bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Experimental clone attempt of http://sourceforge.net/projects/afterglow
331bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        each datum is reduced as src -> event -> dst and the data are graphed.
332bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        by default we have IP.src -> IP.dport -> IP.dst"""
333bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        if src is None:
334b26fe5984bbb57a24c72f50bb536a8f5ba3d528dPhil            src = lambda x: x['IP'].src
335bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        if event is None:
336b26fe5984bbb57a24c72f50bb536a8f5ba3d528dPhil            event = lambda x: x['IP'].dport
337bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        if dst is None:
338b26fe5984bbb57a24c72f50bb536a8f5ba3d528dPhil            dst = lambda x: x['IP'].dst
339bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        sl = {}
340bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        el = {}
341bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        dl = {}
342bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        for i in self.res:
343bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            try:
344bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                s,e,d = src(i),event(i),dst(i)
345bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                if s in sl:
346bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    n,l = sl[s]
347bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    n += 1
348bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    if e not in l:
349bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                        l.append(e)
350bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    sl[s] = (n,l)
351bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                else:
352bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    sl[s] = (1,[e])
353bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                if e in el:
354bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    n,l = el[e]
355bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    n+=1
356bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    if d not in l:
357bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                        l.append(d)
358bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    el[e] = (n,l)
359bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                else:
360bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    el[e] = (1,[d])
361bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                dl[d] = dl.get(d,0)+1
362bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            except:
363bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                continue
364bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
365bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        import math
366bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        def normalize(n):
367bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            return 2+math.log(n)/4.0
368bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
369bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        def minmax(x):
370241e2c497945a93117ce42ebc2a555e3871ca716Pierre LALET            m, M = reduce(lambda a, b: (min(a[0], b[0]), max(a[1], b[1])),
371241e2c497945a93117ce42ebc2a555e3871ca716Pierre LALET                          ((a, a) for a in x))
372bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            if m == M:
373bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                m = 0
374bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            if M == 0:
375bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                M = 1
376241e2c497945a93117ce42ebc2a555e3871ca716Pierre LALET            return m, M
377bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
37822a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotter        mins, maxs = minmax(x for x, _ in six.itervalues(sl))
37922a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotter        mine, maxe = minmax(x for x, _ in six.itervalues(el))
38022a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotter        mind, maxd = minmax(six.itervalues(dl))
381bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
382bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        gr = 'digraph "afterglow" {\n\tedge [len=2.5];\n'
383bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
384bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        gr += "# src nodes\n"
385bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        for s in sl:
386bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            n,l = sl[s]; n = 1+float(n-mins)/(maxs-mins)
387d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotter            gr += '"src.%s" [label = "%s", shape=box, fillcolor="#FF0000", style=filled, fixedsize=1, height=%.2f,width=%.2f];\n' % (repr(s),repr(s),n,n)
388bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        gr += "# event nodes\n"
389bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        for e in el:
390bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            n,l = el[e]; n = n = 1+float(n-mine)/(maxe-mine)
391d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotter            gr += '"evt.%s" [label = "%s", shape=circle, fillcolor="#00FFFF", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (repr(e),repr(e),n,n)
392bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        for d in dl:
393bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            n = dl[d]; n = n = 1+float(n-mind)/(maxd-mind)
394d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotter            gr += '"dst.%s" [label = "%s", shape=triangle, fillcolor="#0000ff", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (repr(d),repr(d),n,n)
395bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
396bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        gr += "###\n"
397bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        for s in sl:
398bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            n,l = sl[s]
399bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            for e in l:
400d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotter                gr += ' "src.%s" -> "evt.%s";\n' % (repr(s),repr(e))
401bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        for e in el:
402bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            n,l = el[e]
403bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            for d in l:
404d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotter                gr += ' "evt.%s" -> "dst.%s";\n' % (repr(e),repr(d))
405bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
406bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        gr += "}"
407bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return do_graph(gr, **kargs)
408bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
409b26fe5984bbb57a24c72f50bb536a8f5ba3d528dPhil
410bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def _dump_document(self, **kargs):
411e02f12feef2f5bf68e1632f01ef3ab6192d35bbbPhil        import pyx
412bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        d = pyx.document.document()
413bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        l = len(self.res)
414f53402a82b096ef1224460412790dba0daf8c60aPierre LALET        for i, res in enumerate(self.res):
415f53402a82b096ef1224460412790dba0daf8c60aPierre LALET            c = self._elt2pkt(res).canvas_dump(**kargs)
416bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            cbb = c.bbox()
417bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            c.text(cbb.left(),cbb.top()+1,r"\font\cmssfont=cmss12\cmssfont{Frame %i/%i}" % (i,l),[pyx.text.size.LARGE])
418bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            if conf.verb >= 2:
4195c620d0941a75b79fb16fd9b1f3957ba0e553f03Pierre LALET                os.write(1, b".")
420bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            d.append(pyx.document.page(c, paperformat=pyx.document.paperformat.A4,
421bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                                       margin=1*pyx.unit.t_cm,
422bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                                       fittosize=1))
423bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return d
424bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
425bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
426bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
427bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def psdump(self, filename = None, **kargs):
428ed95a6a3cea25583d339e564b7c93bdbcbbf9483Guillaume Valadon        """Creates a multi-page postcript file with a psdump of every packet
429bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        filename: name of the file to write to. If empty, a temporary file is used and
430bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                  conf.prog.psreader is called"""
431bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        d = self._dump_document(**kargs)
432bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        if filename is None:
43383c9b88a1ea492cfb2d860df146d193164c0ba80Phil            filename = get_temp_file(autoext=".ps")
434bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            d.writePSfile(filename)
435881980d3999c698e52cbe1299ca2e63dd3838170Guillaume Valadon            with ContextManagerSubprocess("psdump()"):
436881980d3999c698e52cbe1299ca2e63dd3838170Guillaume Valadon                subprocess.Popen([conf.prog.psreader, filename+".ps"])
437bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        else:
438bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            d.writePSfile(filename)
439b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter        print()
440bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
441bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def pdfdump(self, filename = None, **kargs):
442bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """Creates a PDF file with a psdump of every packet
443bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        filename: name of the file to write to. If empty, a temporary file is used and
444bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                  conf.prog.pdfreader is called"""
445bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        d = self._dump_document(**kargs)
446bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        if filename is None:
44783c9b88a1ea492cfb2d860df146d193164c0ba80Phil            filename = get_temp_file(autoext=".pdf")
448bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            d.writePDFfile(filename)
449881980d3999c698e52cbe1299ca2e63dd3838170Guillaume Valadon            with ContextManagerSubprocess("psdump()"):
450881980d3999c698e52cbe1299ca2e63dd3838170Guillaume Valadon                subprocess.Popen([conf.prog.pdfreader, filename+".pdf"])
451bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        else:
452bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            d.writePDFfile(filename)
453b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter        print()
454bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
455bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def sr(self,multi=0):
456bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        """sr([multi=1]) -> (SndRcvList, PacketList)
457bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        Matches packets in the list and return ( (matched couples), (unmatched packets) )"""
458bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        remain = self.res[:]
459bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        sr = []
460bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        i = 0
461bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        while i < len(remain):
462bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            s = remain[i]
463bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            j = i
464bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            while j < len(remain)-1:
465bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                j += 1
466bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                r = remain[j]
467bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                if r.answers(s):
468bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    sr.append((s,r))
469bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    if multi:
470bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                        remain[i]._answered=1
471bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                        remain[j]._answered=2
472bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                        continue
473bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    del(remain[j])
474bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    del(remain[i])
475bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    i -= 1
476bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil                    break
477bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil            i += 1
478bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        if multi:
47952165d0dd55a1071b935d002a41a95210c97f8e7Guillaume Valadon            remain = [x for x in remain if not hasattr(x, "_answered")]
480bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return SndRcvList(sr),PacketList(remain)
481f13602150438b4afd00a46f1dafb4062369cc835Phil
482f13602150438b4afd00a46f1dafb4062369cc835Phil    def sessions(self, session_extractor=None):
483f13602150438b4afd00a46f1dafb4062369cc835Phil        if session_extractor is None:
484f13602150438b4afd00a46f1dafb4062369cc835Phil            def session_extractor(p):
485e28fc9af59ebd347eb70aa90f0317a553cbe2a91Phil                sess = "Other"
486f13602150438b4afd00a46f1dafb4062369cc835Phil                if 'Ether' in p:
487f13602150438b4afd00a46f1dafb4062369cc835Phil                    if 'IP' in p:
488f13602150438b4afd00a46f1dafb4062369cc835Phil                        if 'TCP' in p:
489f13602150438b4afd00a46f1dafb4062369cc835Phil                            sess = p.sprintf("TCP %IP.src%:%r,TCP.sport% > %IP.dst%:%r,TCP.dport%")
490f13602150438b4afd00a46f1dafb4062369cc835Phil                        elif 'UDP' in p:
491f13602150438b4afd00a46f1dafb4062369cc835Phil                            sess = p.sprintf("UDP %IP.src%:%r,UDP.sport% > %IP.dst%:%r,UDP.dport%")
492f13602150438b4afd00a46f1dafb4062369cc835Phil                        elif 'ICMP' in p:
493f13602150438b4afd00a46f1dafb4062369cc835Phil                            sess = p.sprintf("ICMP %IP.src% > %IP.dst% type=%r,ICMP.type% code=%r,ICMP.code% id=%ICMP.id%")
494f13602150438b4afd00a46f1dafb4062369cc835Phil                        else:
495f13602150438b4afd00a46f1dafb4062369cc835Phil                            sess = p.sprintf("IP %IP.src% > %IP.dst% proto=%IP.proto%")
496f13602150438b4afd00a46f1dafb4062369cc835Phil                    elif 'ARP' in p:
497f13602150438b4afd00a46f1dafb4062369cc835Phil                        sess = p.sprintf("ARP %ARP.psrc% > %ARP.pdst%")
498f13602150438b4afd00a46f1dafb4062369cc835Phil                    else:
499f13602150438b4afd00a46f1dafb4062369cc835Phil                        sess = p.sprintf("Ethernet type=%04xr,Ether.type%")
500f13602150438b4afd00a46f1dafb4062369cc835Phil                return sess
501f13602150438b4afd00a46f1dafb4062369cc835Phil        sessions = defaultdict(self.__class__)
502f13602150438b4afd00a46f1dafb4062369cc835Phil        for p in self.res:
503f13602150438b4afd00a46f1dafb4062369cc835Phil            sess = session_extractor(self._elt2pkt(p))
504f13602150438b4afd00a46f1dafb4062369cc835Phil            sessions[sess].append(p)
505f13602150438b4afd00a46f1dafb4062369cc835Phil        return dict(sessions)
5068cd8caea2cbda8001f31ad0f01835d765691ebfePhil
5078cd8caea2cbda8001f31ad0f01835d765691ebfePhil    def replace(self, *args, **kargs):
5088cd8caea2cbda8001f31ad0f01835d765691ebfePhil        """
5098cd8caea2cbda8001f31ad0f01835d765691ebfePhil        lst.replace(<field>,[<oldvalue>,]<newvalue>)
5108cd8caea2cbda8001f31ad0f01835d765691ebfePhil        lst.replace( (fld,[ov],nv),(fld,[ov,]nv),...)
5118cd8caea2cbda8001f31ad0f01835d765691ebfePhil          if ov is None, all values are replaced
5128cd8caea2cbda8001f31ad0f01835d765691ebfePhil        ex:
5138cd8caea2cbda8001f31ad0f01835d765691ebfePhil          lst.replace( IP.src, "192.168.1.1", "10.0.0.1" )
5148cd8caea2cbda8001f31ad0f01835d765691ebfePhil          lst.replace( IP.ttl, 64 )
5158cd8caea2cbda8001f31ad0f01835d765691ebfePhil          lst.replace( (IP.ttl, 64), (TCP.sport, 666, 777), )
5168cd8caea2cbda8001f31ad0f01835d765691ebfePhil        """
5178cd8caea2cbda8001f31ad0f01835d765691ebfePhil        delete_checksums = kargs.get("delete_checksums",False)
5188cd8caea2cbda8001f31ad0f01835d765691ebfePhil        x=PacketList(name="Replaced %s" % self.listname)
519d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotter        if not isinstance(args[0], tuple):
5208cd8caea2cbda8001f31ad0f01835d765691ebfePhil            args = (args,)
5218cd8caea2cbda8001f31ad0f01835d765691ebfePhil        for p in self.res:
5228cd8caea2cbda8001f31ad0f01835d765691ebfePhil            p = self._elt2pkt(p)
5238cd8caea2cbda8001f31ad0f01835d765691ebfePhil            copied = False
5248cd8caea2cbda8001f31ad0f01835d765691ebfePhil            for scheme in args:
5258cd8caea2cbda8001f31ad0f01835d765691ebfePhil                fld = scheme[0]
5268cd8caea2cbda8001f31ad0f01835d765691ebfePhil                old = scheme[1] # not used if len(scheme) == 2
5278cd8caea2cbda8001f31ad0f01835d765691ebfePhil                new = scheme[-1]
5288cd8caea2cbda8001f31ad0f01835d765691ebfePhil                for o in fld.owners:
5298cd8caea2cbda8001f31ad0f01835d765691ebfePhil                    if o in p:
5308cd8caea2cbda8001f31ad0f01835d765691ebfePhil                        if len(scheme) == 2 or p[o].getfieldval(fld.name) == old:
5318cd8caea2cbda8001f31ad0f01835d765691ebfePhil                            if not copied:
5328cd8caea2cbda8001f31ad0f01835d765691ebfePhil                                p = p.copy()
5338cd8caea2cbda8001f31ad0f01835d765691ebfePhil                                if delete_checksums:
5348cd8caea2cbda8001f31ad0f01835d765691ebfePhil                                    p.delete_checksums()
5358cd8caea2cbda8001f31ad0f01835d765691ebfePhil                                copied = True
5368cd8caea2cbda8001f31ad0f01835d765691ebfePhil                            setattr(p[o], fld.name, new)
5378cd8caea2cbda8001f31ad0f01835d765691ebfePhil            x.append(p)
5388cd8caea2cbda8001f31ad0f01835d765691ebfePhil        return x
539bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
540bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil
541bb2ddd8ef0416706e645595b6b5484ee4f409ad3Philclass SndRcvList(PacketList):
542aefe6fcbe454cd014487523c5470d933fa70e95cPierre LALET    __slots__ = []
543bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def __init__(self, res=None, name="Results", stats=None):
544bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        PacketList.__init__(self, res, name, stats)
545bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def _elt2pkt(self, elt):
546bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return elt[1]
547bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil    def _elt2sum(self, elt):
548bb2ddd8ef0416706e645595b6b5484ee4f409ad3Phil        return "%s ==> %s" % (elt[0].summary(),elt[1].summary())
549