Skip to content

Commit f1f9563

Browse files
committed
Added VTP as contrib (ticket #179)
1 parent 92f8b12 commit f1f9563

1 file changed

Lines changed: 171 additions & 0 deletions

File tree

scapy/contrib/vtp.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#!/usr/bin/env python
2+
3+
# scapy.contrib.description = VLAN Trunking Protocol (VTP)
4+
# scapy.contrib.status = loads
5+
6+
"""
7+
VTP Scapy Extension
8+
~~~~~~~~~~~~~~~~~~~~~
9+
10+
:version: 2009-02-15
11+
:copyright: 2009 by Jochen Bartl
12+
:e-mail: lobo@c3a.de / jochen.bartl@gmail.com
13+
:license: GPL v2
14+
15+
This program is free software; you can redistribute it and/or
16+
modify it under the terms of the GNU General Public License
17+
as published by the Free Software Foundation; either version 2
18+
of the License, or (at your option) any later version.
19+
20+
This program is distributed in the hope that it will be useful,
21+
but WITHOUT ANY WARRANTY; without even the implied warranty of
22+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23+
GNU General Public License for more details.
24+
25+
:TODO
26+
27+
- Join messages
28+
- RE MD5 hash calculation
29+
- Have a closer look at 8 byte padding in summary adv.
30+
"debug sw-vlan vtp packets" sais the TLV length is invalid,
31+
when I change the values
32+
'\x00\x00\x00\x01\x06\x01\x00\x02'
33+
* \x00\x00 ?
34+
* \x00\x01 tlvtype?
35+
* \x06 length?
36+
* \x00\x02 value?
37+
- h2i function for VTPTimeStampField
38+
39+
:References:
40+
41+
- Understanding VLAN Trunk Protocol (VTP)
42+
http://www.cisco.com/en/US/tech/tk389/tk689/technologies_tech_note09186a0080094c52.shtml
43+
"""
44+
45+
from scapy.all import *
46+
47+
_VTP_VLAN_TYPE = {
48+
1 : 'Ethernet',
49+
2 : 'FDDI',
50+
3 : 'TrCRF',
51+
4 : 'FDDI-net',
52+
5 : 'TrBRF'
53+
}
54+
55+
_VTP_VLANINFO_TLV_TYPE = {
56+
0x01 : 'Source-Routing Ring Number',
57+
0x02 : 'Source-Routing Bridge Number',
58+
0x03 : 'Spanning-Tree Protocol Type',
59+
0x04 : 'Parent VLAN',
60+
0x05 : 'Translationally Bridged VLANs',
61+
0x06 : 'Pruning',
62+
0x07 : 'Bridge Type',
63+
0x08 : 'Max ARE Hop Count',
64+
0x09 : 'Max STE Hop Count',
65+
0x0A : 'Backup CRF Mode'
66+
}
67+
68+
69+
class VTPVlanInfoTlv(Packet):
70+
name = "VTP VLAN Info TLV"
71+
fields_desc = [
72+
ByteEnumField("type", 0, _VTP_VLANINFO_TLV_TYPE),
73+
ByteField("length", 0),
74+
StrLenField("value", None, length_from=lambda pkt : pkt.length + 1)
75+
]
76+
77+
def guess_payload_class(self, p):
78+
return Padding
79+
80+
class VTPVlanInfo(Packet):
81+
name = "VTP VLAN Info"
82+
fields_desc = [
83+
ByteField("len", None), # FIXME: compute length
84+
ByteEnumField("status", 0, {0 : "active", 1 : "suspended"}),
85+
ByteEnumField("type", 1, _VTP_VLAN_TYPE),
86+
FieldLenField("vlannamelen", None, "vlanname", "B"),
87+
ShortField("vlanid", 1),
88+
ShortField("mtu", 1500),
89+
XIntField("dot10index", None),
90+
StrLenField("vlanname", "default", length_from=lambda pkt:4 * ((pkt.vlannamelen + 3) / 4)),
91+
ConditionalField(PacketListField("tlvlist", [], VTPVlanInfoTlv,
92+
length_from=lambda pkt:pkt.len - 12 - (4 * ((pkt.vlannamelen + 3) / 4))),
93+
lambda pkt:pkt.type not in [1, 2])
94+
]
95+
96+
def post_build(self, p, pay):
97+
vlannamelen = 4 * ((len(self.vlanname) + 3) / 4)
98+
99+
if self.len == None:
100+
l = vlannamelen + 12
101+
p = chr(l & 0xff) + p[1:]
102+
103+
# Pad vlan name with zeros if vlannamelen > len(vlanname)
104+
l = vlannamelen - len(self.vlanname)
105+
if l != 0:
106+
p += "\x00" * l
107+
108+
p += pay
109+
110+
return p
111+
112+
def guess_payload_class(self, p):
113+
return Padding
114+
115+
_VTP_Types = {
116+
1 : 'Summary Advertisement',
117+
2 : 'Subset Advertisements',
118+
3 : 'Advertisement Request',
119+
4 : 'Join'
120+
}
121+
122+
class VTPTimeStampField(StrFixedLenField):
123+
def __init__(self, name, default):
124+
StrFixedLenField.__init__(self, name, default, 12)
125+
126+
def i2repr(self, pkt, x):
127+
return "%s-%s-%s %s:%s:%s" % (x[:2], x[2:4], x[4:6], x[6:8], x[8:10], x[10:12])
128+
129+
class VTP(Packet):
130+
name = "VTP"
131+
fields_desc = [
132+
ByteField("ver", 2),
133+
ByteEnumField("code", 1, _VTP_Types),
134+
ConditionalField(ByteField("followers", 1),
135+
lambda pkt:pkt.code == 1),
136+
ConditionalField(ByteField("seq", 1),
137+
lambda pkt:pkt.code == 2),
138+
ConditionalField(ByteField("reserved", 0),
139+
lambda pkt:pkt.code == 3),
140+
ByteField("domnamelen", None),
141+
StrFixedLenField("domname", "manbearpig", 32),
142+
ConditionalField(SignedIntField("rev", 0),
143+
lambda pkt:pkt.code == 1 or
144+
pkt.code == 2),
145+
# updater identity
146+
ConditionalField(IPField("uid", "192.168.0.1"),
147+
lambda pkt:pkt.code == 1),
148+
ConditionalField(VTPTimeStampField("timestamp", '930301000000'),
149+
lambda pkt:pkt.code == 1),
150+
ConditionalField(StrFixedLenField("md5", "\x00" * 16, 16),
151+
lambda pkt:pkt.code == 1),
152+
ConditionalField(
153+
PacketListField("vlaninfo", [], VTPVlanInfo),
154+
lambda pkt: pkt.code == 2),
155+
ConditionalField(ShortField("startvalue", 0),
156+
lambda pkt:pkt.code == 3)
157+
]
158+
159+
def post_build(self, p, pay):
160+
if self.domnamelen == None:
161+
domnamelen = len(self.domname.strip("\x00"))
162+
p = p[:3] + chr(domnamelen & 0xff) + p[4:]
163+
164+
p += pay
165+
166+
return p
167+
168+
bind_layers(SNAP, VTP, code=0x2003)
169+
170+
if __name__ == '__main__':
171+
interact(mydict=globals(), mybanner="VTP")

0 commit comments

Comments
 (0)