diff --git a/scapy/plist.py b/scapy/plist.py index 3dc64866dc686ff972b2db68d6f5799b0ceab46b..987d39db105d3cd8364159a11837cd0faa772b58 100644 --- a/scapy/plist.py +++ b/scapy/plist.py @@ -284,25 +284,41 @@ lfilter: truth function to apply to each packet to decide whether it will be dis def conversations(self, getsrcdst=None,**kargs): """Graphes a conversations between sources and destinations and display it (using graphviz and imagemagick) - getsrcdst: a function that takes an element of the list and return the source and dest - by defaults, return source and destination IP + getsrcdst: a function that takes an element of the list and + returns the source, the destination and optionally + a label. By default, returns the IP source and + destination from IP and ARP layers type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option target: filename or redirect. Defaults pipe to Imagemagick's display program prog: which graphviz program to use""" if getsrcdst is None: - getsrcdst = lambda x:(x['IP'].src, x['IP'].dst) + def getsrcdst(pkt): + if IP in pkt: + return (pkt[IP].src, pkt[IP].dst) + if ARP in pkt: + return (pkt[ARP].psrc, pkt[ARP].pdst) + raise TypeError() conv = {} for p in self.res: p = self._elt2pkt(p) try: c = getsrcdst(p) except: - #XXX warning() + # No warning here: it's OK that getsrcdst() raises an + # exception, since it might be, for example, a + # function that expects a specific layer in each + # packet. The try/except approach is faster and + # considered more Pythonic than adding tests. continue - conv[c] = conv.get(c,0)+1 + if len(c) == 3: + conv.setdefault(c[:2], set()).add(c[2]) + else: + conv[c] = conv.get(c, 0) + 1 gr = 'digraph "conv" {\n' - for s,d in conv: - gr += '\t "%s" -> "%s"\n' % (s,d) + for (s, d), l in conv.iteritems(): + gr += '\t "%s" -> "%s" [label="%s"]\n' % ( + s, d, ', '.join(str(x) for x in l) if isinstance(l, set) else l + ) gr += "}\n" return do_graph(gr, **kargs)