Ticket #115: scapy_dtp.py

File scapy_dtp.py, 4.0 kB (added by lobo@c3a.de, 5 months ago)

DTP protocol dissector

Line 
1 #!/usr/bin/env python
2 """
3     DTP Scapy Extension
4     ~~~~~~~~~~~~~~~~~~~~~
5
6     :version: 2008-06-19
7     :author: Jochen Bartl <lobo@c3a.de>
8
9     :Thanks:
10
11     - TLV code derived from the CDP implementation of scapy. (Thanks to Nicolas Bareil and Arnaud Ebalard)
12         http://trac.secdev.org/scapy/ticket/18
13 """
14
15 from scapy import *
16
17 class GenericTlv(Packet):
18     name = "Generic TLV"
19     fields_desc = [ XShortField("type", 0x0001),
20             FieldLenField("length", None, length_of=lambda pkt:pkt.value + 4),
21             StrLenField("value", "", length_from=lambda pkt:pkt.length - 4)
22             ]
23
24     def guess_payload_class(self, p):
25         return Padding
26
27 class RepeatedTlvListField(PacketListField):
28     def __init__(self, name, default, cls):
29         PacketField.__init__(self, name, default, cls)
30
31     def getfield(self, pkt, s):
32         lst = []
33         remain = s
34         while len(remain) > 0:
35             p = self.m2i(pkt,remain)
36             if Padding in p:
37                 pad = p[Padding]
38                 remain = pad.load
39                 del(pad.underlayer.payload)
40             else:
41                 remain = ""
42             lst.append(p)
43         return remain,lst
44
45     def addfield(self, pkt, s, val):
46         return s+reduce(str.__add__, map(str, val),"")
47
48 _DTP_TLV_CLS = {
49                     0x0001 : "DTPDomain",
50                     0x0002 : "DTPStatus",
51                     0x0003 : "DTPType",
52                     0x0004 : "DTPNeighbor"
53                    }
54
55 _DTP_TLV_NAME = {
56                     0x0001 : "Domain",
57                     0x0002 : "Status",
58                     0x0003 : "Type",
59                     0x0004 : "Neighbor"
60                    }
61
62 class DTPDomain(Packet):
63     name = "DTP Domain"
64     fields_desc = [ XShortEnumField("type", 0x0001, _DTP_TLV_NAME),
65             FieldLenField("length", None, "domain", adjust=lambda pkt,x:x + 4),
66             StrLenField("domain", "", length_from=lambda pkt:pkt.length - 4)
67             ]
68
69     def guess_payload_class(self, p):
70         return Padding
71
72 class DTPStatus(Packet):
73     name = "DTP Status"
74     fields_desc = [ XShortEnumField("type", 0x0002, _DTP_TLV_NAME),
75             FieldLenField("length", None, "status", adjust=lambda pkt,x:x + 4),
76             StrLenField("status", "", length_from=lambda pkt:pkt.length - 4)
77             ]
78
79     def guess_payload_class(self, p):
80         return Padding
81
82 class DTPType(Packet):
83     name = "DTP Type"
84     fields_desc = [ XShortEnumField("type", 0x0003, _DTP_TLV_NAME),
85             FieldLenField("length", None, "dtptype", adjust=lambda pkt,x:x + 4),
86             StrLenField("dtptype", "", length_from=lambda pkt:pkt.length - 4)
87             ]
88
89     def guess_payload_class(self, p):
90         return Padding
91
92 class DTPNeighbor(Packet):
93     name = "DTP Neighbor"
94     fields_desc = [ XShortEnumField("type", 0x0004, _DTP_TLV_NAME),
95             FieldLenField("length", None, "neighbor", adjust=lambda pkt,x:x + 4),
96             MACField("neighbor", None)
97             ]
98
99     def guess_payload_class(self, p):
100         return Padding
101
102 def _DTPGuessPayloadClass(p, **kargs):
103     cls = Raw
104     if len(p) >= 2:
105         t = struct.unpack("!H", p[:2])[0]
106         #clsname = _dtp_tlv_cls.get(t, "Raw")
107         clsname = _DTP_TLV_CLS.get(t, "GenericTlv")
108         cls = globals()[clsname]
109         return cls(p, **kargs)
110
111 class DTP(Packet):
112     name = "DTP"
113     fields_desc = [ ByteField("ver", 1),
114                     RepeatedTlvListField("tlvlist", [], _DTPGuessPayloadClass)
115                 ]
116
117 bind_layers(SNAP, DTP, code=0x2004, OUI=0xc)
118
119
120 def negotiate_trunk(iface=conf.iface, mymac=str(RandMAC())):
121     print "Trying to negotiate a trunk on interface %s" % iface
122
123     p = Dot3(src=mymac, dst="01:00:0c:cc:cc:cc")/LLC()/SNAP()/DTP(ver=1, tlvlist=[DTPDomain(length=13, type=1, domain="\x00\x00\x00\x00\x00\x00\x00\x00\x00"),DTPStatus(status="\x03", length=5, type=2),DTPType(length=5, type=3, dtptype="\xa5"),DTPNeighbor(length=10, type=4, neighbor=mymac)])
124     sendp(p)
125
126 if __name__ == "__main__":
127     interact(mydict=globals(), mybanner="DTP")