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

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

## 317 statements

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

16 from struct import unpack

17 import socket

18

19 from impacket.ImpactPacket import Header, array_tobytes

20 from impacket import LOG

21

22 IP_ADDRESS_LENGTH = 4

23

24 class 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

39 class 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

89 def get_byte(buffer, offset):

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

91

92 def get_word(buffer, offset):

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

94

95 def get_long(buffer, offset):

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

97

98 def get_bytes(buffer, offset, bytes):

99 return buffer[offset: offset + bytes]

100

101 def 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

110 class 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

136 class 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

148 class 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

179 class 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

224 class 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

237 class 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

298 class 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

311 class 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

324 class 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

339 class 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

370 class 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

380 class 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

392 class 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

403 class 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

415 class 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

427 class ManagementAddresses(Address):

428 Type = 0x16

429

430 def get_type(self):

431 return ManagementAddresses.Type

432

433 class MTU(CDPElement):

434 Type = 0x11

435

436 def get_type(self):

437 return MTU.Type

438

439 class SystemName(CDPElement):

440 Type = 0x14

441

442 def get_type(self):

443 return SystemName.Type

444

445 class SystemObjectId(CDPElement):

446 Type = 0x15

447

448 def get_type(self):

449 return SystemObjectId.Type

450

451 class SnmpLocation(CDPElement):

452 Type = 0x17

453

454 def get_type(self):

455 return SnmpLocation.Type

456

457

458 class DummyCdpElement(CDPElement):

459 Type = 0x99

460

461 def get_type(self):

462 return DummyCdpElement.Type

463

464 class 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 )