Hide keyboard shortcuts

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# 

15 

16from struct import unpack 

17import socket 

18 

19from impacket.ImpactPacket import Header, array_tobytes 

20from impacket import LOG 

21 

22IP_ADDRESS_LENGTH = 4 

23 

24class CDPTypes: 

25 

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 

38 

39class CDP(Header): 

40 

41 Type = 0x2000 

42 OUI = 0x00000c 

43 

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) 

49 

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 

59 

60 def get_header_size(self): 

61 return 8 

62 

63 def get_version(self): 

64 return self.get_byte(0) 

65 

66 def get_ttl(self): 

67 return self.get_byte(1) 

68 

69 def get_checksum(self): 

70 return self.get_word(2) 

71 

72 def get_type(self): 

73 return self.get_word(4) 

74 

75 def get_lenght(self): 

76 return self.get_word(6) 

77 

78 def getElements(self): 

79 return self._elements 

80 

81 

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 

87 

88 

89def get_byte(buffer, offset): 

90 return unpack("!B", buffer[offset:offset+1])[0] 

91 

92def get_word(buffer, offset): 

93 return unpack("!h", buffer[offset:offset+2])[0] 

94 

95def get_long(buffer, offset): 

96 return unpack("!I", buffer[offset:offset+4])[0] 

97 

98def get_bytes(buffer, offset, bytes): 

99 return buffer[offset:offset + bytes] 

100 

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] 

107 

108 

109 

110class CDPElement(Header): 

111 

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] ) 

117 

118 @classmethod 

119 def Get_length(cls, aBuffer): 

120 return unpack('!h', aBuffer[2:4])[0] 

121 

122 def get_header_size(self): 

123 self._length 

124 

125 def get_length(self): 

126 return self.get_word(2) 

127 

128 def get_data(self): 

129 return array_tobytes(self.get_bytes())[4:self.get_length()] 

130 

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 ) 

135 

136class CDPDevice(CDPElement): 

137 Type = 1 

138 

139 def get_type(self): 

140 return CDPDevice.Type 

141 

142 def get_device_id(self): 

143 return CDPElement.get_data(self) 

144 

145 def __str__(self): 

146 return "Device:" + self.get_device_id() 

147 

148class Address(CDPElement): 

149 Type = 2 

150 

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) 

156 

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():] 

163 

164 def get_type(self): 

165 return Address.Type 

166 

167 def get_number(self): 

168 return self.get_long(4) 

169 

170 def get_address_details(self): 

171 return self.address_details 

172 

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 

178 

179class AddressDetails(): 

180 

181 PROTOCOL_IP = 0xcc 

182 

183 @classmethod 

184 def create(cls, buff): 

185 a = AddressDetails(buff) 

186 return a 

187 

188 

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] 

194 

195 def get_total_length(self): 

196 return self.total_length 

197 

198 def get_protocol_type(self): 

199 return self.buffer[0:1] 

200 

201 def get_protocol_length(self): 

202 return get_byte( self.buffer, 1) 

203 

204 def get_protocol(self): 

205 return get_byte( self.buffer, 2) 

206 

207 def get_address_length(self): 

208 return get_word( self.buffer, 3) 

209 

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 

217 

218 def is_protocol_IP(self): 

219 return self.get_protocol()==AddressDetails.PROTOCOL_IP 

220 

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()) 

223 

224class Port(CDPElement): 

225 Type = 3 

226 

227 def get_type(self): 

228 return Port.Type 

229 

230 def get_port(self): 

231 return CDPElement.get_data(self) 

232 

233 def __str__(self): 

234 return "Port:" + self.get_port() 

235 

236 

237class Capabilities(CDPElement): 

238 Type = 4 

239 

240 def __init__(self, aBuffer = None): 

241 CDPElement.__init__(self, aBuffer) 

242 self._capabilities_processed = False 

243 

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() 

252 

253 def get_type(self): 

254 return Capabilities.Type 

255 

256 def get_capabilities(self): 

257 return CDPElement.get_data(self) 

258 

259 def _init_capabilities(self): 

260 if self._capabilities_processed: 

261 return 

262 

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 

271 

272 def is_router(self): 

273 return self._router 

274 

275 def is_transparent_bridge(self): 

276 return self._transparent_bridge 

277 

278 def is_source_route_bridge(self): 

279 return self._source_route_bridge 

280 

281 def is_switch(self): 

282 return self._switch 

283 

284 def is_host(self): 

285 return self.is_host 

286 

287 def is_igmp_capable(self): 

288 return self._igmp_capable 

289 

290 def is_repeater(self): 

291 return self._repeater 

292 

293 

294 def __str__(self): 

295 return "Capabilities:" + self.get_capabilities() 

296 

297 

298class SoftVersion(CDPElement): 

299 Type = 5 

300 

301 def get_type(self): 

302 return SoftVersion.Type 

303 

304 def get_version(self): 

305 return CDPElement.get_data(self) 

306 

307 def __str__(self): 

308 return "Version:" + self.get_version() 

309 

310 

311class Platform(CDPElement): 

312 Type = 6 

313 

314 def get_type(self): 

315 return Platform.Type 

316 

317 def get_platform(self): 

318 return CDPElement.get_data(self) 

319 

320 def __str__(self): 

321 return "Platform:%r" % self.get_platform() 

322 

323 

324class IpPrefix(CDPElement): 

325 Type = 7 

326 

327 def get_type(self): 

328 return IpPrefix .Type 

329 

330 def get_ip_prefix(self): 

331 return CDPElement.get_ip_address(self, 4) 

332 

333 def get_bits(self): 

334 return self.get_byte(8) 

335 

336 def __str__(self): 

337 return "IP Prefix/Gateway: %r/%d" % (self.get_ip_prefix(), self.get_bits()) 

338 

339class ProtocolHello(CDPElement): 

340 Type = 8 

341 

342 def get_type(self): 

343 return ProtocolHello.Type 

344 

345 def get_master_ip(self): 

346 return self.get_ip_address(9) 

347 

348 def get_version(self): 

349 return self.get_byte(17) 

350 

351 def get_sub_version(self): 

352 return self.get_byte(18) 

353 

354 def get_status(self): 

355 return self.get_byte(19) 

356 

357 def get_cluster_command_mac(self): 

358 return array_tobytes(self.get_bytes())[20:20+6] 

359 

360 def get_switch_mac(self): 

361 return array_tobytes(self.get_bytes())[28:28+6] 

362 

363 def get_management_vlan(self): 

364 return self.get_word(36) 

365 

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()) 

369 

370class VTPManagementDomain(CDPElement): 

371 Type = 9 

372 

373 def get_type(self): 

374 return VTPManagementDomain.Type 

375 

376 def get_domain(self): 

377 return CDPElement.get_data(self) 

378 

379 

380class Duplex(CDPElement): 

381 Type = 0xb 

382 

383 def get_type(self): 

384 return Duplex.Type 

385 

386 def get_duplex(self): 

387 return CDPElement.get_data(self) 

388 

389 def is_full_duplex(self): 

390 return self.get_duplex()==0x1 

391 

392class VLAN(CDPElement): 

393 Type = 0xa 

394 

395 def get_type(self): 

396 return VLAN.Type 

397 

398 def get_vlan_number(self): 

399 return CDPElement.get_data(self) 

400 

401 

402 

403class TrustBitmap(CDPElement): 

404 Type = 0x12 

405 

406 def get_type(self): 

407 return TrustBitmap.Type 

408 

409 def get_trust_bitmap(self): 

410 return self.get_data() 

411 

412 def __str__(self): 

413 return "TrustBitmap Trust Bitmap:%r" % self.get_trust_bitmap() 

414 

415class UntrustedPortCoS(CDPElement): 

416 Type = 0x13 

417 

418 def get_type(self): 

419 return UntrustedPortCoS.Type 

420 

421 def get_port_CoS(self): 

422 return self.get_data() 

423 

424 def __str__(self): 

425 return "UntrustedPortCoS port CoS %r" % self.get_port_CoS() 

426 

427class ManagementAddresses(Address): 

428 Type = 0x16 

429 

430 def get_type(self): 

431 return ManagementAddresses.Type 

432 

433class MTU(CDPElement): 

434 Type = 0x11 

435 

436 def get_type(self): 

437 return MTU.Type 

438 

439class SystemName(CDPElement): 

440 Type = 0x14 

441 

442 def get_type(self): 

443 return SystemName.Type 

444 

445class SystemObjectId(CDPElement): 

446 Type = 0x15 

447 

448 def get_type(self): 

449 return SystemObjectId.Type 

450 

451class SnmpLocation(CDPElement): 

452 Type = 0x17 

453 

454 def get_type(self): 

455 return SnmpLocation.Type 

456 

457 

458class DummyCdpElement(CDPElement): 

459 Type = 0x99 

460 

461 def get_type(self): 

462 return DummyCdpElement.Type 

463 

464class CDPElementFactory(): 

465 

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 } 

486 

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 )