Home | History | Annotate | Download | only in contrib
      1 #!/usr/bin/env python
      2 
      3 # This file is part of Scapy
      4 # Scapy is free software: you can redistribute it and/or modify
      5 # it under the terms of the GNU General Public License as published by
      6 # the Free Software Foundation, either version 2 of the License, or
      7 # any later version.
      8 #
      9 # Scapy is distributed in the hope that it will be useful,
     10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     12 # GNU General Public License for more details.
     13 #
     14 # You should have received a copy of the GNU General Public License
     15 # along with Scapy. If not, see <http://www.gnu.org/licenses/>.
     16 
     17 # scapy.contrib.description = DTP
     18 # scapy.contrib.status = loads
     19 
     20 """
     21     DTP Scapy Extension
     22     ~~~~~~~~~~~~~~~~~~~
     23 
     24     :version: 2008-12-22
     25     :author: Jochen Bartl <lobo (at] c3a.de>
     26 
     27     :Thanks:
     28 
     29     - TLV code derived from the CDP implementation of scapy. (Thanks to Nicolas Bareil and Arnaud Ebalard)
     30         http://trac.secdev.org/scapy/ticket/18
     31 """
     32 
     33 from __future__ import absolute_import
     34 from __future__ import print_function
     35 from scapy.packet import *
     36 from scapy.fields import *
     37 from scapy.layers.l2 import SNAP,Dot3,LLC
     38 from scapy.sendrecv import sendp
     39 
     40 class DtpGenericTlv(Packet):
     41     name = "DTP Generic TLV"
     42     fields_desc = [ XShortField("type", 0x0001),
     43             FieldLenField("length", None, length_of=lambda pkt:pkt.value + 4),
     44             StrLenField("value", "", length_from=lambda pkt:pkt.length - 4)
     45             ]
     46 
     47     def guess_payload_class(self, p):
     48         return conf.padding_layer
     49 
     50 class RepeatedTlvListField(PacketListField):
     51     def __init__(self, name, default, cls):
     52         PacketField.__init__(self, name, default, cls)
     53 
     54     def getfield(self, pkt, s):
     55         lst = []
     56         remain = s
     57         while len(remain) > 0:
     58             p = self.m2i(pkt,remain)
     59             if conf.padding_layer in p:
     60                 pad = p[conf.padding_layer]
     61                 remain = pad.load
     62                 del(pad.underlayer.payload)
     63             else:
     64                 remain = ""
     65             lst.append(p)
     66         return remain,lst
     67 
     68     def addfield(self, pkt, s, val):
     69         return s + ''.join(str(v) for v in val)
     70 
     71 _DTP_TLV_CLS = {
     72                     0x0001 : "DTPDomain",
     73                     0x0002 : "DTPStatus",
     74                     0x0003 : "DTPType",
     75                     0x0004 : "DTPNeighbor"
     76                    }
     77 
     78 class DTPDomain(DtpGenericTlv):
     79     name = "DTP Domain"
     80     fields_desc = [ ShortField("type", 1),
     81             FieldLenField("length", None, "domain", adjust=lambda pkt,x:x + 4),
     82             StrLenField("domain", b"\x00", length_from=lambda pkt:pkt.length - 4)
     83             ]
     84 
     85 class DTPStatus(DtpGenericTlv):
     86     name = "DTP Status"
     87     fields_desc = [ ShortField("type", 2),
     88             FieldLenField("length", None, "status", adjust=lambda pkt,x:x + 4),
     89             StrLenField("status", b"\x03", length_from=lambda pkt:pkt.length - 4)
     90             ]
     91 
     92 class DTPType(DtpGenericTlv):
     93     name = "DTP Type"
     94     fields_desc = [ ShortField("type", 3),
     95             FieldLenField("length", None, "dtptype", adjust=lambda pkt,x:x + 4),
     96             StrLenField("dtptype", b"\xa5", length_from=lambda pkt:pkt.length - 4)
     97             ]
     98 
     99 class DTPNeighbor(DtpGenericTlv):
    100     name = "DTP Neighbor"
    101     fields_desc = [ ShortField("type", 4),
    102             #FieldLenField("length", None, "neighbor", adjust=lambda pkt,x:x + 4),
    103             ShortField("len", 10),
    104             MACField("neighbor", None)
    105             ]
    106 
    107 def _DTPGuessPayloadClass(p, **kargs):
    108     cls = conf.raw_layer
    109     if len(p) >= 2:
    110         t = struct.unpack("!H", p[:2])[0]
    111         clsname = _DTP_TLV_CLS.get(t, "DtpGenericTlv")
    112         cls = globals()[clsname]
    113     return cls(p, **kargs)
    114 
    115 class DTP(Packet):
    116     name = "DTP"
    117     fields_desc = [ ByteField("ver", 1),
    118                     RepeatedTlvListField("tlvlist", [], _DTPGuessPayloadClass)
    119                 ]
    120 
    121 bind_layers(SNAP, DTP, code=0x2004, OUI=0xc)
    122 
    123 
    124 def negotiate_trunk(iface=conf.iface, mymac=str(RandMAC())):
    125     print("Trying to negotiate a trunk on interface %s" % iface)
    126     p = Dot3(src=mymac, dst="01:00:0c:cc:cc:cc")/LLC()/SNAP()/DTP(tlvlist=[DTPDomain(),DTPStatus(),DTPType(),DTPNeighbor(neighbor=mymac)])
    127     sendp(p)
    128 
    129 if __name__ == "__main__":
    130     from scapy.main import interact
    131     interact(mydict=globals(), mybanner="DTP")
    132