# This file is part of Scapy
|
# Scapy is free software: you can redistribute it and/or modify
|
# it under the terms of the GNU General Public License as published by
|
# the Free Software Foundation, either version 2 of the License, or
|
# any later version.
|
#
|
# Scapy is distributed in the hope that it will be useful,
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# GNU General Public License for more details.
|
#
|
# You should have received a copy of the GNU General Public License
|
# along with Scapy. If not, see <http://www.gnu.org/licenses/>.
|
|
# scapy.contrib.description = VLAN Trunking Protocol (VTP)
|
# scapy.contrib.status = loads
|
|
"""
|
VTP Scapy Extension
|
~~~~~~~~~~~~~~~~~~~~~
|
|
:version: 2009-02-15
|
:copyright: 2009 by Jochen Bartl
|
:e-mail: lobo@c3a.de / jochen.bartl@gmail.com
|
:license: GPL v2
|
|
This program is free software; you can redistribute it and/or
|
modify it under the terms of the GNU General Public License
|
as published by the Free Software Foundation; either version 2
|
of the License, or (at your option) any later version.
|
|
This program is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU General Public License for more details.
|
|
:TODO
|
|
- Join messages
|
- RE MD5 hash calculation
|
- Have a closer look at 8 byte padding in summary adv.
|
"debug sw-vlan vtp packets" sais the TLV length is invalid,
|
when I change the values
|
b'\x00\x00\x00\x01\x06\x01\x00\x02'
|
* \x00\x00 ?
|
* \x00\x01 tlvtype?
|
* \x06 length?
|
* \x00\x02 value?
|
- h2i function for VTPTimeStampField
|
|
:References:
|
|
- Understanding VLAN Trunk Protocol (VTP)
|
http://www.cisco.com/en/US/tech/tk389/tk689/technologies_tech_note09186a0080094c52.shtml
|
"""
|
|
from scapy.packet import *
|
from scapy.fields import *
|
from scapy.layers.l2 import *
|
|
_VTP_VLAN_TYPE = {
|
1 : 'Ethernet',
|
2 : 'FDDI',
|
3 : 'TrCRF',
|
4 : 'FDDI-net',
|
5 : 'TrBRF'
|
}
|
|
_VTP_VLANINFO_TLV_TYPE = {
|
0x01 : 'Source-Routing Ring Number',
|
0x02 : 'Source-Routing Bridge Number',
|
0x03 : 'Spanning-Tree Protocol Type',
|
0x04 : 'Parent VLAN',
|
0x05 : 'Translationally Bridged VLANs',
|
0x06 : 'Pruning',
|
0x07 : 'Bridge Type',
|
0x08 : 'Max ARE Hop Count',
|
0x09 : 'Max STE Hop Count',
|
0x0A : 'Backup CRF Mode'
|
}
|
|
|
class VTPVlanInfoTlv(Packet):
|
name = "VTP VLAN Info TLV"
|
fields_desc = [
|
ByteEnumField("type", 0, _VTP_VLANINFO_TLV_TYPE),
|
ByteField("length", 0),
|
StrLenField("value", None, length_from=lambda pkt : pkt.length + 1)
|
]
|
|
def guess_payload_class(self, p):
|
return conf.padding_layer
|
|
class VTPVlanInfo(Packet):
|
name = "VTP VLAN Info"
|
fields_desc = [
|
ByteField("len", None), # FIXME: compute length
|
ByteEnumField("status", 0, {0 : "active", 1 : "suspended"}),
|
ByteEnumField("type", 1, _VTP_VLAN_TYPE),
|
FieldLenField("vlannamelen", None, "vlanname", "B"),
|
ShortField("vlanid", 1),
|
ShortField("mtu", 1500),
|
XIntField("dot10index", None),
|
StrLenField("vlanname", "default", length_from=lambda pkt:4 * ((pkt.vlannamelen + 3) / 4)),
|
ConditionalField(PacketListField("tlvlist", [], VTPVlanInfoTlv,
|
length_from=lambda pkt:pkt.len - 12 - (4 * ((pkt.vlannamelen + 3) / 4))),
|
lambda pkt:pkt.type not in [1, 2])
|
]
|
|
def post_build(self, p, pay):
|
vlannamelen = 4 * ((len(self.vlanname) + 3) / 4)
|
|
if self.len == None:
|
l = vlannamelen + 12
|
p = chr(l & 0xff) + p[1:]
|
|
# Pad vlan name with zeros if vlannamelen > len(vlanname)
|
l = vlannamelen - len(self.vlanname)
|
if l != 0:
|
p += b"\x00" * l
|
|
p += pay
|
|
return p
|
|
def guess_payload_class(self, p):
|
return conf.padding_layer
|
|
_VTP_Types = {
|
1 : 'Summary Advertisement',
|
2 : 'Subset Advertisements',
|
3 : 'Advertisement Request',
|
4 : 'Join'
|
}
|
|
class VTPTimeStampField(StrFixedLenField):
|
def __init__(self, name, default):
|
StrFixedLenField.__init__(self, name, default, 12)
|
|
def i2repr(self, pkt, x):
|
return "%s-%s-%s %s:%s:%s" % (x[:2], x[2:4], x[4:6], x[6:8], x[8:10], x[10:12])
|
|
class VTP(Packet):
|
name = "VTP"
|
fields_desc = [
|
ByteField("ver", 2),
|
ByteEnumField("code", 1, _VTP_Types),
|
ConditionalField(ByteField("followers", 1),
|
lambda pkt:pkt.code == 1),
|
ConditionalField(ByteField("seq", 1),
|
lambda pkt:pkt.code == 2),
|
ConditionalField(ByteField("reserved", 0),
|
lambda pkt:pkt.code == 3),
|
ByteField("domnamelen", None),
|
StrFixedLenField("domname", "manbearpig", 32),
|
ConditionalField(SignedIntField("rev", 0),
|
lambda pkt:pkt.code == 1 or
|
pkt.code == 2),
|
# updater identity
|
ConditionalField(IPField("uid", "192.168.0.1"),
|
lambda pkt:pkt.code == 1),
|
ConditionalField(VTPTimeStampField("timestamp", '930301000000'),
|
lambda pkt:pkt.code == 1),
|
ConditionalField(StrFixedLenField("md5", b"\x00" * 16, 16),
|
lambda pkt:pkt.code == 1),
|
ConditionalField(
|
PacketListField("vlaninfo", [], VTPVlanInfo),
|
lambda pkt: pkt.code == 2),
|
ConditionalField(ShortField("startvalue", 0),
|
lambda pkt:pkt.code == 3)
|
]
|
|
def post_build(self, p, pay):
|
if self.domnamelen == None:
|
domnamelen = len(self.domname.strip(b"\x00"))
|
p = p[:3] + chr(domnamelen & 0xff) + p[4:]
|
|
p += pay
|
|
return p
|
|
bind_layers(SNAP, VTP, code=0x2003)
|
|
if __name__ == '__main__':
|
from scapy.main import interact
|
interact(mydict=globals(), mybanner="VTP")
|