Coverage for /root/GitHubProjects/impacket/impacket/cdp.py : 47%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Impacket - Collection of Python classes for working with network protocols.
2#
3# SECUREAUTH LABS. Copyright (C) 2021 SecureAuth Corporation. All rights reserved.
4#
5# This software is provided under a slightly modified version
6# of the Apache Software License. See the accompanying LICENSE file
7# for more information.
8#
9# Description:
10# Cisco Discovery Protocol packet codecs.
11#
12# Author:
13# Martin Candurra
14#
16from struct import unpack
17import socket
19from impacket.ImpactPacket import Header, array_tobytes
20from impacket import LOG
22IP_ADDRESS_LENGTH = 4
24class CDPTypes:
26 DeviceID_Type = 1
27 Address_Type = 2
28 PortID_Type = 3
29 Capabilities_Type = 4
30 SoftVersion_Type = 5
31 Platform_Type = 6
32 IPPrefix_Type = 7
33 ProtocolHello_Type = 8
34 MTU_Type = 17
35 SystemName_Type = 20
36 SystemObjectId_Type = 21
37 SnmpLocation = 23
39class CDP(Header):
41 Type = 0x2000
42 OUI = 0x00000c
44 def __init__(self, aBuffer = None):
45 Header.__init__(self, 8)
46 if aBuffer:
47 self.load_header(aBuffer)
48 self._elements = self._getElements(aBuffer)
50 def _getElements(self, aBuffer):
51 # Remove version (1 byte), TTL (1 byte), and checksum (2 bytes)
52 buff = aBuffer[4:]
53 l = []
54 while buff:
55 elem = CDPElementFactory.create(buff)
56 l.append( elem )
57 buff = buff[ elem.get_length() : ]
58 return l
60 def get_header_size(self):
61 return 8
63 def get_version(self):
64 return self.get_byte(0)
66 def get_ttl(self):
67 return self.get_byte(1)
69 def get_checksum(self):
70 return self.get_word(2)
72 def get_type(self):
73 return self.get_word(4)
75 def get_lenght(self):
76 return self.get_word(6)
78 def getElements(self):
79 return self._elements
82 def __str__(self):
83 tmp_str = 'CDP Details:\n'
84 for element in self._elements:
85 tmp_str += "** Type:" + str(element.get_type()) + " " + str(element) + "\n"
86 return tmp_str
89def get_byte(buffer, offset):
90 return unpack("!B", buffer[offset:offset+1])[0]
92def get_word(buffer, offset):
93 return unpack("!h", buffer[offset:offset+2])[0]
95def get_long(buffer, offset):
96 return unpack("!I", buffer[offset:offset+4])[0]
98def get_bytes(buffer, offset, bytes):
99 return buffer[offset:offset + bytes]
101def mac_to_string(mac_bytes):
102 bytes = unpack('!BBBBBB', mac_bytes)
103 s = ''
104 for byte in bytes:
105 s += '%02x:' % byte
106 return s[0:-1]
110class CDPElement(Header):
112 def __init__(self, aBuffer = None):
113 Header.__init__(self, 8)
114 if aBuffer:
115 self._length = CDPElement.Get_length(aBuffer)
116 self.load_header( aBuffer[:self._length] )
118 @classmethod
119 def Get_length(cls, aBuffer):
120 return unpack('!h', aBuffer[2:4])[0]
122 def get_header_size(self):
123 self._length
125 def get_length(self):
126 return self.get_word(2)
128 def get_data(self):
129 return array_tobytes(self.get_bytes())[4:self.get_length()]
131 def get_ip_address(self, offset = 0, ip = None):
132 if not ip:
133 ip = array_tobytes(self.get_bytes())[offset : offset + IP_ADDRESS_LENGTH]
134 return socket.inet_ntoa( ip )
136class CDPDevice(CDPElement):
137 Type = 1
139 def get_type(self):
140 return CDPDevice.Type
142 def get_device_id(self):
143 return CDPElement.get_data(self)
145 def __str__(self):
146 return "Device:" + self.get_device_id()
148class Address(CDPElement):
149 Type = 2
151 def __init__(self, aBuffer = None):
152 CDPElement.__init__(self, aBuffer)
153 if aBuffer:
154 data = array_tobytes(self.get_bytes())[8:]
155 self._generateAddressDetails(data)
157 def _generateAddressDetails(self, buff):
158 self.address_details = []
159 while buff:
160 address = AddressDetails.create(buff)
161 self.address_details.append( address )
162 buff = buff[address.get_total_length():]
164 def get_type(self):
165 return Address.Type
167 def get_number(self):
168 return self.get_long(4)
170 def get_address_details(self):
171 return self.address_details
173 def __str__(self):
174 tmp_str = "Addresses:"
175 for address_detail in self.address_details:
176 tmp_str += "\n" + str(address_detail)
177 return tmp_str
179class AddressDetails():
181 PROTOCOL_IP = 0xcc
183 @classmethod
184 def create(cls, buff):
185 a = AddressDetails(buff)
186 return a
189 def __init__(self, aBuffer = None):
190 if aBuffer:
191 addr_length = unpack("!h", aBuffer[3:5])[0]
192 self.total_length = addr_length + 5
193 self.buffer = aBuffer[:self.total_length]
195 def get_total_length(self):
196 return self.total_length
198 def get_protocol_type(self):
199 return self.buffer[0:1]
201 def get_protocol_length(self):
202 return get_byte( self.buffer, 1)
204 def get_protocol(self):
205 return get_byte( self.buffer, 2)
207 def get_address_length(self):
208 return get_word( self.buffer, 3)
210 def get_address(self):
211 address = get_bytes( self.buffer, 5, self.get_address_length() )
212 if self.get_protocol()==AddressDetails.PROTOCOL_IP:
213 return socket.inet_ntoa(address)
214 else:
215 LOG.error("Address not IP")
216 return address
218 def is_protocol_IP(self):
219 return self.get_protocol()==AddressDetails.PROTOCOL_IP
221 def __str__(self):
222 return "Protocol Type:%r Protocol:%r Address Length:%r Address:%s" % (self.get_protocol_type(), self.get_protocol(), self.get_address_length(), self.get_address())
224class Port(CDPElement):
225 Type = 3
227 def get_type(self):
228 return Port.Type
230 def get_port(self):
231 return CDPElement.get_data(self)
233 def __str__(self):
234 return "Port:" + self.get_port()
237class Capabilities(CDPElement):
238 Type = 4
240 def __init__(self, aBuffer = None):
241 CDPElement.__init__(self, aBuffer)
242 self._capabilities_processed = False
244 self._router = False
245 self._transparent_bridge = False
246 self._source_route_bridge = False
247 self._switch = False
248 self._host = False
249 self._igmp_capable = False
250 self._repeater = False
251 self._init_capabilities()
253 def get_type(self):
254 return Capabilities.Type
256 def get_capabilities(self):
257 return CDPElement.get_data(self)
259 def _init_capabilities(self):
260 if self._capabilities_processed:
261 return
263 capabilities = unpack("!L", self.get_capabilities())[0]
264 self._router = (capabilities & 0x1) > 0
265 self._transparent_bridge = (capabilities & 0x02) > 0
266 self._source_route_bridge = (capabilities & 0x04) > 0
267 self._switch = (capabilities & 0x08) > 0
268 self._host = (capabilities & 0x10) > 0
269 self._igmp_capable = (capabilities & 0x20) > 0
270 self._repeater = (capabilities & 0x40) > 0
272 def is_router(self):
273 return self._router
275 def is_transparent_bridge(self):
276 return self._transparent_bridge
278 def is_source_route_bridge(self):
279 return self._source_route_bridge
281 def is_switch(self):
282 return self._switch
284 def is_host(self):
285 return self.is_host
287 def is_igmp_capable(self):
288 return self._igmp_capable
290 def is_repeater(self):
291 return self._repeater
294 def __str__(self):
295 return "Capabilities:" + self.get_capabilities()
298class SoftVersion(CDPElement):
299 Type = 5
301 def get_type(self):
302 return SoftVersion.Type
304 def get_version(self):
305 return CDPElement.get_data(self)
307 def __str__(self):
308 return "Version:" + self.get_version()
311class Platform(CDPElement):
312 Type = 6
314 def get_type(self):
315 return Platform.Type
317 def get_platform(self):
318 return CDPElement.get_data(self)
320 def __str__(self):
321 return "Platform:%r" % self.get_platform()
324class IpPrefix(CDPElement):
325 Type = 7
327 def get_type(self):
328 return IpPrefix .Type
330 def get_ip_prefix(self):
331 return CDPElement.get_ip_address(self, 4)
333 def get_bits(self):
334 return self.get_byte(8)
336 def __str__(self):
337 return "IP Prefix/Gateway: %r/%d" % (self.get_ip_prefix(), self.get_bits())
339class ProtocolHello(CDPElement):
340 Type = 8
342 def get_type(self):
343 return ProtocolHello.Type
345 def get_master_ip(self):
346 return self.get_ip_address(9)
348 def get_version(self):
349 return self.get_byte(17)
351 def get_sub_version(self):
352 return self.get_byte(18)
354 def get_status(self):
355 return self.get_byte(19)
357 def get_cluster_command_mac(self):
358 return array_tobytes(self.get_bytes())[20:20+6]
360 def get_switch_mac(self):
361 return array_tobytes(self.get_bytes())[28:28+6]
363 def get_management_vlan(self):
364 return self.get_word(36)
366 def __str__(self):
367 return "\n\n\nProcolHello: Master IP:%s version:%r subversion:%r status:%r Switch's Mac:%r Management VLAN:%r" \
368 % (self.get_master_ip(), self.get_version(), self.get_sub_version(), self.get_status(), mac_to_string(self.get_switch_mac()), self.get_management_vlan())
370class VTPManagementDomain(CDPElement):
371 Type = 9
373 def get_type(self):
374 return VTPManagementDomain.Type
376 def get_domain(self):
377 return CDPElement.get_data(self)
380class Duplex(CDPElement):
381 Type = 0xb
383 def get_type(self):
384 return Duplex.Type
386 def get_duplex(self):
387 return CDPElement.get_data(self)
389 def is_full_duplex(self):
390 return self.get_duplex()==0x1
392class VLAN(CDPElement):
393 Type = 0xa
395 def get_type(self):
396 return VLAN.Type
398 def get_vlan_number(self):
399 return CDPElement.get_data(self)
403class TrustBitmap(CDPElement):
404 Type = 0x12
406 def get_type(self):
407 return TrustBitmap.Type
409 def get_trust_bitmap(self):
410 return self.get_data()
412 def __str__(self):
413 return "TrustBitmap Trust Bitmap:%r" % self.get_trust_bitmap()
415class UntrustedPortCoS(CDPElement):
416 Type = 0x13
418 def get_type(self):
419 return UntrustedPortCoS.Type
421 def get_port_CoS(self):
422 return self.get_data()
424 def __str__(self):
425 return "UntrustedPortCoS port CoS %r" % self.get_port_CoS()
427class ManagementAddresses(Address):
428 Type = 0x16
430 def get_type(self):
431 return ManagementAddresses.Type
433class MTU(CDPElement):
434 Type = 0x11
436 def get_type(self):
437 return MTU.Type
439class SystemName(CDPElement):
440 Type = 0x14
442 def get_type(self):
443 return SystemName.Type
445class SystemObjectId(CDPElement):
446 Type = 0x15
448 def get_type(self):
449 return SystemObjectId.Type
451class SnmpLocation(CDPElement):
452 Type = 0x17
454 def get_type(self):
455 return SnmpLocation.Type
458class DummyCdpElement(CDPElement):
459 Type = 0x99
461 def get_type(self):
462 return DummyCdpElement.Type
464class CDPElementFactory():
466 elementTypeMap = {
467 CDPDevice.Type : CDPDevice,
468 Port.Type : Port,
469 Capabilities.Type : Capabilities,
470 Address.Type : Address,
471 SoftVersion.Type : SoftVersion,
472 Platform.Type : Platform,
473 IpPrefix.Type : IpPrefix,
474 ProtocolHello.Type : ProtocolHello,
475 VTPManagementDomain.Type : VTPManagementDomain,
476 VLAN.Type : VLAN,
477 Duplex.Type : Duplex,
478 TrustBitmap.Type : TrustBitmap,
479 UntrustedPortCoS.Type : UntrustedPortCoS,
480 ManagementAddresses.Type : ManagementAddresses,
481 MTU.Type : MTU,
482 SystemName.Type : SystemName,
483 SystemObjectId.Type : SystemObjectId,
484 SnmpLocation.Type : SnmpLocation
485 }
487 @classmethod
488 def create(cls, aBuffer):
489# print "CDPElementFactory.create aBuffer:", repr(aBuffer)
490# print "CDPElementFactory.create sub_type:", repr(aBuffer[0:2])
491 _type = unpack("!h", aBuffer[0:2])[0]
492# print "CDPElementFactory.create _type:", _type
493 try:
494 class_type = cls.elementTypeMap[_type]
495 except KeyError:
496 class_type = DummyCdpElement
497 #raise Exception("CDP Element type %s not implemented" % _type)
498 return class_type( aBuffer )