| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
from scapy import * |
|---|
| 23 |
import __builtin__ |
|---|
| 24 |
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
def get_cls(name, fallback_cls): |
|---|
| 31 |
return __builtin__.__dict__.get(name, fallback_cls) |
|---|
| 32 |
|
|---|
| 33 |
|
|---|
| 34 |
|
|---|
| 35 |
_cdp_tlv_cls = { 0x0001: "CDPMsgDeviceID", |
|---|
| 36 |
0x0002: "CDPMsgAddr", |
|---|
| 37 |
0x0003: "CDPMsgPortID", |
|---|
| 38 |
0x0004: "CDPMsgCapabilities", |
|---|
| 39 |
0x0005: "CDPMsgSoftwareVersion", |
|---|
| 40 |
0x0006: "CDPMsgPlatform", |
|---|
| 41 |
0x0007: "CDPMsgIPPrefix", |
|---|
| 42 |
0x0008: "CDPMsgProtoHello", |
|---|
| 43 |
0x0009: "CDPMsgVTPMgmtDomain", |
|---|
| 44 |
0x000a: "CDPMsgNativeVLAN", |
|---|
| 45 |
0x000b: "CDPMsgDuplex", |
|---|
| 46 |
0x000c: "CDPMsgGeneric", |
|---|
| 47 |
0x000d: "CDPMsgGeneric", |
|---|
| 48 |
0x000e: "CDPMsgVoIPVLANReply", |
|---|
| 49 |
0x000f: "CDPMsgVoIPVLANQuery", |
|---|
| 50 |
0x0010: "CDPMsgPower", |
|---|
| 51 |
0x0011: "CDPMsgMTU", |
|---|
| 52 |
0x0012: "CDPMsgTrustBitmap", |
|---|
| 53 |
0x0013: "CDPMsgUntrustedPortCoS", |
|---|
| 54 |
0x0014: "CDPMsgSystemName", |
|---|
| 55 |
0x0015: "CDPMsgSystemOID", |
|---|
| 56 |
0x0016: "CDPMsgMgmtAddr", |
|---|
| 57 |
0x0017: "CDPMsgLocation", |
|---|
| 58 |
0x0019: "CDPMsgUnknown19" } |
|---|
| 59 |
|
|---|
| 60 |
_cdp_tlv_types = { 0x0001: "Device ID", |
|---|
| 61 |
0x0002: "Addresses", |
|---|
| 62 |
0x0003: "Port ID", |
|---|
| 63 |
0x0004: "Capabilities", |
|---|
| 64 |
0x0005: "Software Version", |
|---|
| 65 |
0x0006: "Platform", |
|---|
| 66 |
0x0007: "IP Prefix", |
|---|
| 67 |
0x0008: "Protocol Hello", |
|---|
| 68 |
0x0009: "VTP Mangement Domain", |
|---|
| 69 |
0x000a: "Native VLAN", |
|---|
| 70 |
0x000b: "Duplex", |
|---|
| 71 |
0x000c: "CDP Unknown command (send us a pcap file)", |
|---|
| 72 |
0x000d: "CDP Unknown command (send us a pcap file)", |
|---|
| 73 |
0x000e: "VoIP VLAN Reply", |
|---|
| 74 |
0x000f: "VoIP VLAN Query", |
|---|
| 75 |
0x0010: "Power", |
|---|
| 76 |
0x0011: "MTU", |
|---|
| 77 |
0x0012: "Trust Bitmap", |
|---|
| 78 |
0x0013: "Untrusted Port CoS", |
|---|
| 79 |
0x0014: "System Name", |
|---|
| 80 |
0x0015: "System OID", |
|---|
| 81 |
0x0016: "Management Address", |
|---|
| 82 |
0x0017: "Location", |
|---|
| 83 |
0x0018: "CDP Unknown command (send us a pcap file)", |
|---|
| 84 |
0x0019: "CDP Unknown command (send us a pcap file)"} |
|---|
| 85 |
|
|---|
| 86 |
def _CDPGuessPayloadClass(p, **kargs): |
|---|
| 87 |
cls = Raw |
|---|
| 88 |
if len(p) >= 2: |
|---|
| 89 |
t = struct.unpack("!H", p[:2])[0] |
|---|
| 90 |
cls = get_cls(_cdp_tlv_cls.get(t, "Raw"), Raw) |
|---|
| 91 |
return cls(p, **kargs) |
|---|
| 92 |
|
|---|
| 93 |
class CDPMsgGeneric(Packet): |
|---|
| 94 |
name = "CDP Generic Message" |
|---|
| 95 |
fields_desc = [ XShortEnumField("type", None, _cdp_tlv_types), |
|---|
| 96 |
FieldLenField("len", None, "val", "!H"), |
|---|
| 97 |
StrLenField("val", "", "len", shift=4) ] |
|---|
| 98 |
|
|---|
| 99 |
def guess_payload_class(self, p): |
|---|
| 100 |
return Padding |
|---|
| 101 |
|
|---|
| 102 |
class CDPMsgDeviceID(CDPMsgGeneric): |
|---|
| 103 |
name = "Device ID" |
|---|
| 104 |
__metaclass__ = NewDefaultValues |
|---|
| 105 |
type = 0x0001 |
|---|
| 106 |
|
|---|
| 107 |
|
|---|
| 108 |
class CDPAddrRecord(Packet): |
|---|
| 109 |
name = "CDP Addresses" |
|---|
| 110 |
fields_desc = [ ByteEnumField("ptype", 0x01, {0x01: "NLPID", |
|---|
| 111 |
0x02: "802.2" }), |
|---|
| 112 |
XByteField("plen", 1), |
|---|
| 113 |
|
|---|
| 114 |
|
|---|
| 115 |
ByteEnumField("proto", 0xCC, {0xCC: "IP"}), |
|---|
| 116 |
ShortField("addrlen", 4), |
|---|
| 117 |
IPField("ipaddr", "0.0.0.0") ] |
|---|
| 118 |
|
|---|
| 119 |
def guess_payload_class(self, p): |
|---|
| 120 |
return Padding |
|---|
| 121 |
|
|---|
| 122 |
|
|---|
| 123 |
class CDPMsgAddr(CDPMsgGeneric): |
|---|
| 124 |
name = "Addresses" |
|---|
| 125 |
fields_desc = [XShortEnumField("type", 0x0002, _cdp_tlv_types), |
|---|
| 126 |
ShortField("len", None), |
|---|
| 127 |
FieldLenField("naddr", None, "addr", "!I"), |
|---|
| 128 |
PacketListField("addr", [], CDPAddrRecord, "naddr") ] |
|---|
| 129 |
|
|---|
| 130 |
def post_build(self, pkt, pay): |
|---|
| 131 |
if self.len is None: |
|---|
| 132 |
l = 8 + len(self.addr) * 9 |
|---|
| 133 |
pkt = pkt[:2] + struct.pack("!H", l) + pkt[4:] |
|---|
| 134 |
p = pkt + pay |
|---|
| 135 |
return p |
|---|
| 136 |
|
|---|
| 137 |
|
|---|
| 138 |
class CDPMsgPortID(CDPMsgGeneric): |
|---|
| 139 |
name = "Port ID" |
|---|
| 140 |
fields_desc = [ XShortEnumField("type", 0x0003, _cdp_tlv_types), |
|---|
| 141 |
FieldLenField("len", None, "iface", "!H"), |
|---|
| 142 |
StrLenField("iface", "Port 1", "len", shift=4) ] |
|---|
| 143 |
|
|---|
| 144 |
|
|---|
| 145 |
_cdp_capabilities = ["Router", |
|---|
| 146 |
"TransparentBridge", |
|---|
| 147 |
"SourceRouteBridge", |
|---|
| 148 |
"Switch", |
|---|
| 149 |
"Host", |
|---|
| 150 |
"IGMPCapable", |
|---|
| 151 |
"Repeater"] + map(lambda x: "Bit%d" % x, range(25,0,-1)) |
|---|
| 152 |
|
|---|
| 153 |
|
|---|
| 154 |
class CDPMsgCapabilities(CDPMsgGeneric): |
|---|
| 155 |
name = "Capabilities" |
|---|
| 156 |
fields_desc = [ XShortEnumField("type", 0x0004, _cdp_tlv_types), |
|---|
| 157 |
ShortField("len", 8), |
|---|
| 158 |
FlagsField("cap", 0, 32, _cdp_capabilities) ] |
|---|
| 159 |
|
|---|
| 160 |
|
|---|
| 161 |
class CDPMsgSoftwareVersion(CDPMsgGeneric): |
|---|
| 162 |
name = "Software Version" |
|---|
| 163 |
__metaclass__ = NewDefaultValues |
|---|
| 164 |
type = 0x0005 |
|---|
| 165 |
|
|---|
| 166 |
|
|---|
| 167 |
class CDPMsgPlatform(CDPMsgGeneric): |
|---|
| 168 |
name = "Platform" |
|---|
| 169 |
__metaclass__ = NewDefaultValues |
|---|
| 170 |
type = 0x0006 |
|---|
| 171 |
|
|---|
| 172 |
_cdp_duplex = { 0x00: "Half", |
|---|
| 173 |
0x01: "Full" } |
|---|
| 174 |
|
|---|
| 175 |
|
|---|
| 176 |
class CDPMsgIPPrefix(CDPMsgGeneric): |
|---|
| 177 |
name = "IP Prefix" |
|---|
| 178 |
|
|---|
| 179 |
|
|---|
| 180 |
|
|---|
| 181 |
class CDPMsgProtoHello(CDPMsgGeneric): |
|---|
| 182 |
name = "Protocol Hello" |
|---|
| 183 |
|
|---|
| 184 |
class CDPMsgVTPMgmtDomain(CDPMsgGeneric): |
|---|
| 185 |
name = "VTP Management Domain" |
|---|
| 186 |
__metaclass__ = NewDefaultValues |
|---|
| 187 |
type = 0x0009 |
|---|
| 188 |
|
|---|
| 189 |
|
|---|
| 190 |
class CDPMsgNativeVLAN(CDPMsgGeneric): |
|---|
| 191 |
name = "VTP Native VLAN" |
|---|
| 192 |
|
|---|
| 193 |
class CDPMsgDuplex(CDPMsgGeneric): |
|---|
| 194 |
name = "Duplex" |
|---|
| 195 |
fields_desc = [XShortEnumField("type", 0x000b, _cdp_tlv_types), |
|---|
| 196 |
ShortField("len", 5), |
|---|
| 197 |
ByteEnumField("duplex", 0x00, _cdp_duplex) ] |
|---|
| 198 |
|
|---|
| 199 |
class CDPMsgVoIPVLANReply(CDPMsgGeneric): |
|---|
| 200 |
name = "VoIP VLAN Reply" |
|---|
| 201 |
fields_desc = [ XShortEnumField("type", 0x000e, _cdp_tlv_types), |
|---|
| 202 |
ShortField("len", 7), |
|---|
| 203 |
ByteField("status?", 1), |
|---|
| 204 |
ShortField("vlan", 1)] |
|---|
| 205 |
|
|---|
| 206 |
|
|---|
| 207 |
|
|---|
| 208 |
class CDPMsgVoIPVLANQuery(CDPMsgGeneric): |
|---|
| 209 |
name = "VoIP VLAN Query" |
|---|
| 210 |
|
|---|
| 211 |
|
|---|
| 212 |
|
|---|
| 213 |
|
|---|
| 214 |
|
|---|
| 215 |
class _CDPPowerField(ShortField): |
|---|
| 216 |
def i2repr(self, pkt, x): |
|---|
| 217 |
if x is None: |
|---|
| 218 |
x = 0 |
|---|
| 219 |
return "%d mW" % x |
|---|
| 220 |
|
|---|
| 221 |
|
|---|
| 222 |
class CDPMsgPower(CDPMsgGeneric): |
|---|
| 223 |
name = "Power" |
|---|
| 224 |
|
|---|
| 225 |
fields_desc = [XShortEnumField("type", 0x0010, _cdp_tlv_types), |
|---|
| 226 |
ShortField("len", 6), |
|---|
| 227 |
_CDPPowerField("power", 1337)] |
|---|
| 228 |
|
|---|
| 229 |
|
|---|
| 230 |
class CDPMsgMTU(CDPMsgGeneric): |
|---|
| 231 |
name = "MTU" |
|---|
| 232 |
|
|---|
| 233 |
fields_desc = [XShortEnumField("type", 0x0011, _cdp_tlv_types), |
|---|
| 234 |
ShortField("len", 6), |
|---|
| 235 |
ShortField("mtu", 1500)] |
|---|
| 236 |
|
|---|
| 237 |
|
|---|
| 238 |
class CDPMsgUnknown19(CDPMsgGeneric): |
|---|
| 239 |
name = "Unknown CDP Message" |
|---|
| 240 |
__metaclass__ = NewDefaultValues |
|---|
| 241 |
type = 0x0019 |
|---|
| 242 |
|
|---|
| 243 |
|
|---|
| 244 |
|
|---|
| 245 |
|
|---|
| 246 |
class CDPMsg(CDPMsgGeneric): |
|---|
| 247 |
name = "CDP " |
|---|
| 248 |
fields_desc = [XShortEnumField("type", None, _cdp_tlv_types), |
|---|
| 249 |
FieldLenField("len", None, "val", "!H") ] |
|---|
| 250 |
|
|---|
| 251 |
|
|---|
| 252 |
class _CDPChecksum: |
|---|
| 253 |
def post_build(self, pkt, pay): |
|---|
| 254 |
p = pkt + pay |
|---|
| 255 |
if self.cksum is None: |
|---|
| 256 |
cksum = checksum(p) |
|---|
| 257 |
p = p[:2] + struct.pack("!H", cksum) + p[4:] |
|---|
| 258 |
return p |
|---|
| 259 |
|
|---|
| 260 |
|
|---|
| 261 |
class AllPacketListField(PacketListField): |
|---|
| 262 |
|
|---|
| 263 |
def __init__(self, name, default, cls): |
|---|
| 264 |
PacketField.__init__(self, name, default, cls) |
|---|
| 265 |
|
|---|
| 266 |
def getfield(self, pkt, s): |
|---|
| 267 |
lst = [] |
|---|
| 268 |
remain = s |
|---|
| 269 |
while len(remain)>0: |
|---|
| 270 |
p = self.m2i(pkt,remain) |
|---|
| 271 |
if Padding in p: |
|---|
| 272 |
pad = p[Padding] |
|---|
| 273 |
remain = pad.load |
|---|
| 274 |
del(pad.underlayer.payload) |
|---|
| 275 |
else: |
|---|
| 276 |
remain = "" |
|---|
| 277 |
lst.append(p) |
|---|
| 278 |
return remain,lst |
|---|
| 279 |
def addfield(self, pkt, s, val): |
|---|
| 280 |
return s+reduce(str.__add__, map(str, val),"") |
|---|
| 281 |
|
|---|
| 282 |
class CDPv2_HDR(_CDPChecksum, CDPMsgGeneric): |
|---|
| 283 |
name = "Cisco Discovery Protocol version 2" |
|---|
| 284 |
fields_desc = [ByteField("vers", 2), |
|---|
| 285 |
ByteField("ttl", 180), |
|---|
| 286 |
XShortField("cksum", None), |
|---|
| 287 |
AllPacketListField("msg", [], _CDPGuessPayloadClass) ] |
|---|
| 288 |
|
|---|
| 289 |
bind_layers(SNAP, CDPv2_HDR, { "code": 0x2000, "OUI": 0xC }) |
|---|
| 290 |
|
|---|
| 291 |
if __name__ == "__main__": |
|---|
| 292 |
interact(mydict=globals(),mybanner="Welcome to Cisco Discovery Protocol add-on") |
|---|
| 293 |
|
|---|
| 294 |
|
|---|
| 295 |
|
|---|
| 296 |
|
|---|
| 297 |
|
|---|
| 298 |
It's still incomplete, we are waiting for the Cisco (and scapy :p) |
|---|
| 299 |
documentation... or not :))) |
|---|
| 300 |
|
|---|
| 301 |
-- |
|---|
| 302 |
Nicolas Bareil http://chdir.org/~nico/ |
|---|
| 303 |
OpenPGP=0xAE4F7057 Fingerprint=34DB22091049FB2F33E6B71580F314DAAE4F7057 |
|---|
| 304 |
|
|---|
| 305 |
|
|---|