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) 2020 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# Author: 

10# Altered source done by Alberto Solino (@agsolino) 

11# 

12# Copyright and license note from Pysmb: 

13# 

14# Copyright (C) 2001 Michael Teo <michaelteo@bigfoot.com> 

15# nmb.py - NetBIOS library 

16# 

17# This software is provided 'as-is', without any express or implied warranty.  

18# In no event will the author be held liable for any damages arising from the  

19# use of this software. 

20# 

21# Permission is granted to anyone to use this software for any purpose,  

22# including commercial applications, and to alter it and redistribute it  

23# freely, subject to the following restrictions: 

24# 

25# 1. The origin of this software must not be misrepresented; you must not  

26# claim that you wrote the original software. If you use this software  

27# in a product, an acknowledgment in the product documentation would be 

28# appreciated but is not required. 

29# 

30# 2. Altered source versions must be plainly marked as such, and must not be  

31# misrepresented as being the original software. 

32# 

33# 3. This notice cannot be removed or altered from any source distribution. 

34# 

35from __future__ import division 

36from __future__ import print_function 

37from __future__ import absolute_import 

38import errno 

39import re 

40import select 

41import socket 

42import string 

43import time 

44import random 

45from struct import pack, unpack 

46from six import byte2int, indexbytes, b 

47 

48from impacket.structure import Structure 

49 

50# Our random number generator 

51try: 

52 rand = random.SystemRandom() 

53except NotImplementedError: 

54 rand = random 

55 pass 

56 

57 

58################################################################################ 

59# CONSTANTS 

60################################################################################ 

61# Taken from socket module reference 

62INADDR_ANY = '0.0.0.0' 

63BROADCAST_ADDR = '<broadcast>' 

64 

65# Default port for NetBIOS name service 

66NETBIOS_NS_PORT = 137 

67# Default port for NetBIOS session service 

68NETBIOS_SESSION_PORT = 139 

69 

70# Default port for SMB session service 

71SMB_SESSION_PORT = 445 

72 

73# Owner Node Type Constants 

74NODE_B = 0x0000 

75NODE_P = 0x2000 

76NODE_M = 0x4000 

77NODE_RESERVED = 0x6000 

78NODE_GROUP = 0x8000 

79NODE_UNIQUE = 0x0 

80 

81# Name Type Constants 

82TYPE_UNKNOWN = 0x01 

83TYPE_WORKSTATION = 0x00 

84TYPE_CLIENT = 0x03 

85TYPE_SERVER = 0x20 

86TYPE_DOMAIN_MASTER = 0x1B 

87TYPE_DOMAIN_CONTROLLER = 0x1C 

88TYPE_MASTER_BROWSER = 0x1D 

89TYPE_BROWSER = 0x1E 

90TYPE_NETDDE = 0x1F 

91TYPE_STATUS = 0x21 

92 

93# Opcodes values 

94OPCODE_QUERY = 0 

95OPCODE_REGISTRATION = 0x5 << 11 

96OPCODE_RELEASE = 0x6 << 11 

97OPCODE_WACK = 0x7 << 11 

98OPCODE_REFRESH = 0x8 << 11 

99OPCODE_REQUEST = 0 << 11 

100OPCODE_RESPONSE = 0x10 << 11 

101 

102# NM_FLAGS 

103NM_FLAGS_BROADCAST = 0x1 << 4 

104NM_FLAGS_UNICAST = 0 << 4 

105NM_FLAGS_RA = 0x8 << 4 

106NM_FLAGS_RD = 0x10 << 4 

107NM_FLAGS_TC = 0x20 << 4 

108NM_FLAGS_AA = 0x40 << 4 

109 

110# QUESTION_TYPE 

111QUESTION_TYPE_NB = 0x20 # NetBIOS general Name Service Resource Record 

112QUESTION_TYPE_NBSTAT = 0x21 # NetBIOS NODE STATUS Resource Record 

113# QUESTION_CLASS 

114QUESTION_CLASS_IN = 0x1 # Internet class 

115 

116# RESOURCE RECORD RR_TYPE field definitions 

117RR_TYPE_A = 0x1 # IP address Resource Record 

118RR_TYPE_NS = 0x2 # Name Server Resource Record 

119RR_TYPE_NULL = 0xA # NULL Resource Record 

120RR_TYPE_NB = 0x20 # NetBIOS general Name Service Resource Record 

121RR_TYPE_NBSTAT = 0x21 # NetBIOS NODE STATUS Resource Record 

122 

123# RESOURCE RECORD RR_CLASS field definitions 

124RR_CLASS_IN = 1 # Internet class 

125 

126# RCODE values 

127RCODE_FMT_ERR = 0x1 # Format Error. Request was invalidly formatted. 

128RCODE_SRV_ERR = 0x2 # Server failure. Problem with NBNS, cannot process name. 

129RCODE_IMP_ERR = 0x4 # Unsupported request error. Allowable only for challenging NBNS when gets an Update type 

130 # registration request. 

131RCODE_RFS_ERR = 0x5 # Refused error. For policy reasons server will not register this name from this host. 

132RCODE_ACT_ERR = 0x6 # Active error. Name is owned by another node. 

133RCODE_CFT_ERR = 0x7 # Name in conflict error. A UNIQUE name is owned by more than one node. 

134 

135# NAME_FLAGS 

136NAME_FLAGS_PRM = 0x0200 # Permanent Name Flag. If one (1) then entry is for the permanent node name. Flag is zero 

137 # (0) for all other names. 

138NAME_FLAGS_ACT = 0x0400 # Active Name Flag. All entries have this flag set to one (1). 

139NAME_FLAG_CNF = 0x0800 # Conflict Flag. If one (1) then name on this node is in conflict. 

140NAME_FLAG_DRG = 0x1000 # Deregister Flag. If one (1) then this name is in the process of being deleted. 

141 

142# NB_FLAGS 

143NB_FLAGS_ONT_B = 0 

144NB_FLAGS_ONT_P = 1 << 13 

145NB_FLAGS_ONT_M = 2 << 13 

146NB_FLAGS_G = 1 << 15 

147 

148NAME_TYPES = {TYPE_UNKNOWN: 'Unknown', TYPE_WORKSTATION: 'Workstation', TYPE_CLIENT: 'Client', 

149 TYPE_SERVER: 'Server', TYPE_DOMAIN_MASTER: 'Domain Master', TYPE_DOMAIN_CONTROLLER: 'Domain Controller', 

150 TYPE_MASTER_BROWSER: 'Master Browser', TYPE_BROWSER: 'Browser Server', TYPE_NETDDE: 'NetDDE Server', 

151 TYPE_STATUS: 'Status'} 

152 

153# NetBIOS Session Types 

154NETBIOS_SESSION_MESSAGE = 0x0 

155NETBIOS_SESSION_REQUEST = 0x81 

156NETBIOS_SESSION_POSITIVE_RESPONSE = 0x82 

157NETBIOS_SESSION_NEGATIVE_RESPONSE = 0x83 

158NETBIOS_SESSION_RETARGET_RESPONSE = 0x84 

159NETBIOS_SESSION_KEEP_ALIVE = 0x85 

160 

161################################################################################ 

162# HELPERS 

163################################################################################ 

164def encode_name(name, nametype, scope): 

165 # ToDo: Rewrite this simpler, we're using less than written 

166 """ 

167 Perform first and second level encoding of name as specified in RFC 1001 (Section 4) 

168  

169 :param string name: the name to encode 

170 :param integer nametype: the name type constants 

171 :param string scope: the name's scope  

172  

173 :return string/bytes: the encoded name. 

174 """ 

175 if name == '*': 

176 name += '\0' * 15 

177 elif len(name) > 15: 

178 name = name[:15] + chr(nametype) 

179 else: 

180 name = name.ljust(15) + chr(nametype) 

181 

182 encoded_name = chr(len(name) * 2) + re.sub('.', _do_first_level_encoding, name) 

183 

184 try: 

185 if isinstance(encoded_name, unicode): 185 ↛ 186,   185 ↛ 1892 missed branches: 1) line 185 didn't jump to line 186, because the condition on line 185 was never true, 2) line 185 didn't jump to line 189, because the condition on line 185 was never false

186 encoded_name = encoded_name.encode('utf-8') 

187 except NameError: 

188 pass 

189 if scope: 189 ↛ 190line 189 didn't jump to line 190, because the condition on line 189 was never true

190 encoded_scope = '' 

191 for s in scope.split('.'): 

192 encoded_scope = encoded_scope + chr(len(s)) + s 

193 

194 return b(encoded_name + encoded_scope) + b'\0' 

195 else: 

196 return b(encoded_name) + b'\0' 

197 

198# Internal method for use in encode_name() 

199def _do_first_level_encoding(m): 

200 s = ord(m.group(0)) 

201 return string.ascii_uppercase[s >> 4] + string.ascii_uppercase[s & 0x0f] 

202 

203def decode_name(name): 

204 # ToDo: Rewrite this simpler, we're using less than written 

205 """ 

206 Perform first and second level decoding of name as specified in RFC 1001 (Section 4) 

207 

208 :param string/bytes name: the name to decode 

209 

210 :return string: the decoded name. 

211 """ 

212 

213 name_length = ord(name[0:1]) 

214 assert name_length == 32 

215 

216 decoded_name = re.sub('..', _do_first_level_decoding, name[1:33].decode('utf-8')) 

217 if name[33:34] == b'\0': 217 ↛ 220line 217 didn't jump to line 220, because the condition on line 217 was never false

218 return 34, decoded_name, '' 

219 else: 

220 decoded_domain = '' 

221 offset = 34 

222 while 1: 

223 domain_length = byte2int(name[offset:offset+1]) 

224 if domain_length == 0: 

225 break 

226 decoded_domain = '.' + name[offset:offset + domain_length].decode('utf-8') 

227 offset += domain_length 

228 return offset + 1, decoded_name, decoded_domain 

229 

230def _do_first_level_decoding(m): 

231 s = m.group(0) 

232 return chr(((ord(s[0]) - ord('A')) << 4) | (ord(s[1]) - ord('A'))) 

233 

234ERRCLASS_QUERY = 0x00 

235ERRCLASS_SESSION = 0xf0 

236ERRCLASS_OS = 0xff 

237 

238QUERY_ERRORS = {0x01: 'Format Error. Request was invalidly formatted', 

239 0x02: 'Server failure. Problem with NBNS, cannot process name.', 

240 0x03: 'Name does not exist', 

241 0x04: 'Unsupported request error. Allowable only for challenging NBNS when gets an Update type registration request.', 

242 0x05: 'Refused error. For policy reasons server will not register this name from this host.', 

243 0x06: 'Active error. Name is owned by another node.', 

244 0x07: 'Name in conflict error. A UNIQUE name is owned by more than one node.', 

245 

246 } 

247 

248SESSION_ERRORS = {0x80: 'Not listening on called name', 

249 0x81: 'Not listening for calling name', 

250 0x82: 'Called name not present', 

251 0x83: 'Sufficient resources', 

252 0x8f: 'Unspecified error' 

253 } 

254 

255class NetBIOSError(Exception): 

256 def __init__(self, error_message='', error_class=None, error_code=None): 

257 self.error_class = error_class 

258 self.error_code = error_code 

259 self.error_msg = error_message 

260 

261 def get_error_code(self): 

262 return self.error 

263 

264 def getErrorCode(self): 

265 return self.get_error_code() 

266 

267 def get_error_string(self): 

268 return str(self) 

269 

270 def getErrorString(self): 

271 return str(self) 

272 

273 def __str__(self): 

274 if self.error_code is not None: 

275 if self.error_code in QUERY_ERRORS: 

276 return '%s-%s(%s)' % (self.error_msg, QUERY_ERRORS[self.error_code], self.error_code) 

277 elif self.error_code in SESSION_ERRORS: 

278 return '%s-%s(%s)' % (self.error_msg, SESSION_ERRORS[self.error_code], self.error_code) 

279 else: 

280 return '%s(%s)' % (self.error_msg, self.error_code) 

281 else: 

282 return '%s' % self.error_msg 

283 

284class NetBIOSTimeout(Exception): 

285 def __init__(self, message = 'The NETBIOS connection with the remote host timed out.'): 

286 Exception.__init__(self, message) 

287 

288################################################################################ 

289# 4.2 NAME SERVER PACKETS 

290################################################################################ 

291class NBNSResourceRecord(Structure): 

292 structure = ( 

293 ('RR_NAME','z=\x00'), 

294 ('RR_TYPE','>H=0'), 

295 ('RR_CLASS','>H=0'), 

296 ('TTL','>L=0'), 

297 ('RDLENGTH','>H-RDATA'), 

298 ('RDATA',':=""'), 

299 ) 

300 

301class NBNodeStatusResponse(NBNSResourceRecord): 

302 def __init__(self, data = 0): 

303 NBNSResourceRecord.__init__(self, data) 

304 self.mac = b'00-00-00-00-00-00' 

305 self.num_names = unpack('B', self['RDATA'][:1])[0] 

306 self.entries = list() 

307 data = self['RDATA'][1:] 

308 for _ in range(self.num_names): 

309 entry = NODE_NAME_ENTRY(data) 

310 data = data[len(entry):] 

311 self.entries.append(entry) 

312 self.statistics = STATISTICS(data) 

313 self.set_mac_in_hexa(self.statistics['UNIT_ID']) 

314 

315 def set_mac_in_hexa(self, data): 

316 data_aux = u'' 

317 for d in bytearray(data): 

318 if data_aux == '': 

319 data_aux = '%02x' % d 

320 else: 

321 data_aux += '-%02x' % d 

322 self.mac = data_aux.upper() 

323 

324 def get_mac(self): 

325 return self.mac 

326 

327 def rawData(self): 

328 res = pack('!B', self.num_names ) 

329 for i in range(0, self.num_names): 

330 res += self.entries[i].getData() 

331 

332class NBPositiveNameQueryResponse(NBNSResourceRecord): 

333 def __init__(self, data = 0): 

334 NBNSResourceRecord.__init__(self, data) 

335 self.entries = [ ] 

336 rdata = self['RDATA'] 

337 while len(rdata) > 0: 

338 entry = ADDR_ENTRY(rdata) 

339 rdata = rdata[len(entry):] 

340 self.entries.append(socket.inet_ntoa(entry['NB_ADDRESS'])) 

341 

342# 4.2.1. GENERAL FORMAT OF NAME SERVICE PACKETS 

343class NAME_SERVICE_PACKET(Structure): 

344 commonHdr = ( 

345 ('NAME_TRN_ID','>H=0'), 

346 ('FLAGS','>H=0'), 

347 ('QDCOUNT','>H=0'), 

348 ('ANCOUNT','>H=0'), 

349 ('NSCOUNT','>H=0'), 

350 ('ARCOUNT','>H=0'), 

351 ) 

352 structure = ( 

353 ('ANSWERS',':'), 

354 ) 

355 

356# 4.2.1.2. QUESTION SECTION 

357class QUESTION_ENTRY(Structure): 

358 commonHdr = ( 

359 ('QUESTION_NAME','z'), 

360 ('QUESTION_TYPE','>H=0'), 

361 ('QUESTION_CLASS','>H=0'), 

362 ) 

363 

364# 4.2.1.3. RESOURCE RECORD 

365class RESOURCE_RECORD(Structure): 

366 structure = ( 

367 ('RR_NAME','z=\x00'), 

368 ('RR_TYPE','>H=0'), 

369 ('RR_CLASS','>H=0'), 

370 ('TTL','>L=0'), 

371 ('RDLENGTH','>H-RDATA'), 

372 ('RDATA',':=""'), 

373 ) 

374 

375# 4.2.2. NAME REGISTRATION REQUEST 

376class NAME_REGISTRATION_REQUEST(NAME_SERVICE_PACKET): 

377 structure = ( 

378 ('QUESTION_NAME', ':'), 

379 ('QUESTION_TYPE', '>H=0'), 

380 ('QUESTION_CLASS', '>H=0'), 

381 ('RR_NAME',':', ), 

382 ('RR_TYPE', '>H=0'), 

383 ('RR_CLASS','>H=0'), 

384 ('TTL', '>L=0'), 

385 ('RDLENGTH', '>H=6'), 

386 ('NB_FLAGS', '>H=0'), 

387 ('NB_ADDRESS', '4s=b""'), 

388 ) 

389 def __init__(self, data=None): 

390 NAME_SERVICE_PACKET.__init__(self,data) 

391 self['FLAGS'] = OPCODE_REQUEST | NM_FLAGS_RD | OPCODE_REGISTRATION 

392 self['QDCOUNT'] = 1 

393 self['ANCOUNT'] = 0 

394 self['NSCOUNT'] = 0 

395 self['ARCOUNT'] = 1 

396 

397 self['QUESTION_TYPE'] = QUESTION_TYPE_NB 

398 self['QUESTION_CLASS'] = QUESTION_CLASS_IN 

399 

400 self['RR_TYPE'] = RR_TYPE_NB 

401 self['RR_CLASS'] = RR_CLASS_IN 

402 

403# 4.2.3. NAME OVERWRITE REQUEST & DEMAND 

404class NAME_OVERWRITE_REQUEST(NAME_REGISTRATION_REQUEST): 

405 def __init__(self, data=None): 

406 NAME_REGISTRATION_REQUEST.__init__(self,data) 

407 self['FLAGS'] = OPCODE_REQUEST | OPCODE_REGISTRATION 

408 self['QDCOUNT'] = 1 

409 self['ANCOUNT'] = 0 

410 self['NSCOUNT'] = 0 

411 self['ARCOUNT'] = 1 

412 

413# 4.2.4. NAME REFRESH REQUEST 

414class NAME_REFRESH_REQUEST(NAME_REGISTRATION_REQUEST): 

415 def __init__(self, data=None): 

416 NAME_REGISTRATION_REQUEST.__init__(self,data) 

417 self['FLAGS'] = OPCODE_REFRESH | 0x1 

418 self['QDCOUNT'] = 1 

419 self['ANCOUNT'] = 0 

420 self['NSCOUNT'] = 0 

421 self['ARCOUNT'] = 1 

422 

423# 4.2.5. POSITIVE NAME REGISTRATION RESPONSE 

424# 4.2.6. NEGATIVE NAME REGISTRATION RESPONSE 

425# 4.2.7. END-NODE CHALLENGE REGISTRATION RESPONSE 

426class NAME_REGISTRATION_RESPONSE(NAME_REGISTRATION_REQUEST): 

427 def __init__(self, data=None): 

428 NAME_REGISTRATION_REQUEST.__init__(self,data) 

429 

430# 4.2.8. NAME CONFLICT DEMAND 

431class NAME_CONFLICT_DEMAND(NAME_REGISTRATION_REQUEST): 

432 def __init__(self, data=None): 

433 NAME_REGISTRATION_REQUEST.__init__(self,data) 

434 

435# ToDo: 4.2.9. NAME RELEASE REQUEST & DEMAND 

436# ToDo: 4.2.10. POSITIVE NAME RELEASE RESPONSE 

437# ToDo: 4.2.11. NEGATIVE NAME RELEASE RESPONSE 

438 

439# 4.2.12. NAME QUERY REQUEST 

440class NAME_QUERY_REQUEST(NAME_SERVICE_PACKET): 

441 structure = ( 

442 ('QUESTION_NAME', ':'), 

443 ('QUESTION_TYPE', '>H=0'), 

444 ('QUESTION_CLASS', '>H=0'), 

445 ) 

446 def __init__(self, data=None): 

447 NAME_SERVICE_PACKET.__init__(self,data) 

448 self['FLAGS'] = OPCODE_REQUEST | OPCODE_REGISTRATION | NM_FLAGS_RD 

449 self['RCODE'] = 0 

450 self['QDCOUNT'] = 1 

451 self['ANCOUNT'] = 0 

452 self['NSCOUNT'] = 0 

453 self['ARCOUNT'] = 0 

454 

455 self['QUESTION_TYPE'] = QUESTION_TYPE_NB 

456 self['QUESTION_CLASS'] = QUESTION_CLASS_IN 

457 

458# 4.2.13. POSITIVE NAME QUERY RESPONSE 

459class ADDR_ENTRY(Structure): 

460 structure = ( 

461 ('NB_FLAGS', '>H=0'), 

462 ('NB_ADDRESS', '4s=b""'), 

463 ) 

464 

465# ToDo: 4.2.15. REDIRECT NAME QUERY RESPONSE 

466# ToDo: 4.2.16. WAIT FOR ACKNOWLEDGEMENT (WACK) RESPONSE 

467 

468# 4.2.17. NODE STATUS REQUEST 

469class NODE_STATUS_REQUEST(NAME_QUERY_REQUEST): 

470 def __init__(self, data=None): 

471 NAME_QUERY_REQUEST.__init__(self,data) 

472 

473 self['FLAGS'] = 0 

474 self['QUESTION_TYPE'] = QUESTION_TYPE_NBSTAT 

475 

476# 4.2.18. NODE STATUS RESPONSE 

477class NODE_NAME_ENTRY(Structure): 

478 structure = ( 

479 ('NAME','15s=b""'), 

480 ('TYPE','B=0'), 

481 ('NAME_FLAGS','>H'), 

482 ) 

483 

484class STATISTICS(Structure): 

485 structure = ( 

486 ('UNIT_ID','6s=b""'), 

487 ('JUMPERS','B'), 

488 ('TEST_RESULT','B'), 

489 ('VERSION_NUMBER','>H'), 

490 ('PERIOD_OF_STATISTICS','>H'), 

491 ('NUMBER_OF_CRCs','>H'), 

492 ('NUMBER_ALIGNMENT_ERRORS','>H'), 

493 ('NUMBER_OF_COLLISIONS','>H'), 

494 ('NUMBER_SEND_ABORTS','>H'), 

495 ('NUMBER_GOOD_SENDS','>L'), 

496 ('NUMBER_GOOD_RECEIVES','>L'), 

497 ('NUMBER_RETRANSMITS','>H'), 

498 ('NUMBER_NO_RESOURCE_CONDITIONS','>H'), 

499 ('NUMBER_FREE_COMMAND_BLOCKS','>H'), 

500 ('TOTAL_NUMBER_COMMAND_BLOCKS','>H'), 

501 ('MAX_TOTAL_NUMBER_COMMAND_BLOCKS','>H'), 

502 ('NUMBER_PENDING_SESSIONS','>H'), 

503 ('MAX_NUMBER_PENDING_SESSIONS','>H'), 

504 ('MAX_TOTAL_SESSIONS_POSSIBLE','>H'), 

505 ('SESSION_DATA_PACKET_SIZE','>H'), 

506 ) 

507 

508class NetBIOS: 

509 # Creates a NetBIOS instance without specifying any default NetBIOS domain nameserver. 

510 # All queries will be sent through the servport. 

511 def __init__(self, servport = NETBIOS_NS_PORT): 

512 self.__servport = NETBIOS_NS_PORT 

513 self.__nameserver = None 

514 self.__broadcastaddr = BROADCAST_ADDR 

515 self.mac = b'00-00-00-00-00-00' 

516 

517 def _setup_connection(self, dstaddr, timeout=None): 

518 port = rand.randint(10000, 60000) 

519 af, socktype, proto, _canonname, _sa = socket.getaddrinfo(dstaddr, port, socket.AF_INET, socket.SOCK_DGRAM)[0] 

520 s = socket.socket(af, socktype, proto) 

521 has_bind = 1 

522 for _i in range(0, 10): 

523 # We try to bind to a port for 10 tries 

524 try: 

525 s.bind((INADDR_ANY, rand.randint(10000, 60000))) 

526 s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 

527 has_bind = 1 

528 except socket.error: 

529 pass 

530 if not has_bind: 530 ↛ 531line 530 didn't jump to line 531, because the condition on line 530 was never true

531 raise NetBIOSError('Cannot bind to a good UDP port', ERRCLASS_OS, errno.EAGAIN) 

532 self.__sock = s 

533 

534 def send(self, request, destaddr, timeout): 

535 self._setup_connection(destaddr) 

536 

537 tries = 3 

538 while 1: 

539 try: 

540 self.__sock.sendto(request.getData(), 0, (destaddr, self.__servport)) 

541 ready, _, _ = select.select([self.__sock.fileno()], [], [], timeout) 

542 if not ready: 

543 if tries: 

544 # Retry again until tries == 0 

545 tries -= 1 

546 else: 

547 raise NetBIOSTimeout 

548 else: 

549 try: 

550 data, _ = self.__sock.recvfrom(65536, 0) 

551 except Exception as e: 

552 raise NetBIOSError("recvfrom error: %s" % str(e)) 

553 self.__sock.close() 

554 res = NAME_SERVICE_PACKET(data) 

555 if res['NAME_TRN_ID'] == request['NAME_TRN_ID']: 555 ↛ 539line 555 didn't jump to line 539, because the condition on line 555 was never false

556 if (res['FLAGS'] & 0xf) > 0: 556 ↛ 557line 556 didn't jump to line 557, because the condition on line 556 was never true

557 raise NetBIOSError('Negative response', ERRCLASS_QUERY, res['FLAGS'] & 0xf) 

558 return res 

559 except select.error as ex: 559 ↛ 560line 559 didn't jump to line 560, because the exception caught by line 559 didn't happen

560 if ex.errno != errno.EINTR and ex.errno != errno.EAGAIN: 

561 raise NetBIOSError('Error occurs while waiting for response', ERRCLASS_OS, ex.errno) 

562 except socket.error as ex: 

563 raise NetBIOSError('Connection error: %s' % str(ex)) 

564 

565 # Set the default NetBIOS domain nameserver. 

566 def set_nameserver(self, nameserver): 

567 self.__nameserver = nameserver 

568 

569 # Return the default NetBIOS domain nameserver, or None if none is specified. 

570 def get_nameserver(self): 

571 return self.__nameserver 

572 

573 # Set the broadcast address to be used for query. 

574 def set_broadcastaddr(self, broadcastaddr): 

575 self.__broadcastaddr = broadcastaddr 

576 

577 # Return the broadcast address to be used, or BROADCAST_ADDR if default broadcast address is used.  

578 def get_broadcastaddr(self): 

579 return self.__broadcastaddr 

580 

581 # Returns a NBPositiveNameQueryResponse instance containing the host information for nbname. 

582 # If a NetBIOS domain nameserver has been specified, it will be used for the query. 

583 # Otherwise, the query is broadcasted on the broadcast address. 

584 def gethostbyname(self, nbname, qtype = TYPE_WORKSTATION, scope = None, timeout = 1): 

585 resp = self.name_query_request(nbname, self.__nameserver, qtype, scope, timeout) 

586 return resp 

587 

588 # Returns a list of NBNodeEntry instances containing node status information for nbname. 

589 # If destaddr contains an IP address, then this will become an unicast query on the destaddr. 

590 # Raises NetBIOSTimeout if timeout (in secs) is reached. 

591 # Raises NetBIOSError for other errors 

592 def getnodestatus(self, nbname, destaddr = None, type = TYPE_WORKSTATION, scope = None, timeout = 1): 

593 if destaddr: 593 ↛ 596line 593 didn't jump to line 596, because the condition on line 593 was never false

594 return self.node_status_request(nbname, destaddr, type, scope, timeout) 

595 else: 

596 return self.node_status_request(nbname, self.__nameserver, type, scope, timeout) 

597 

598 def getnetbiosname(self, ip): 

599 entries = self.getnodestatus('*',ip) 

600 entries = [x for x in entries if x['TYPE'] == TYPE_SERVER] 

601 return entries[0]['NAME'].strip().decode('latin-1') 

602 

603 def getmacaddress(self): 

604 return self.mac 

605 

606 def name_registration_request(self, nbname, destaddr, qtype, scope, nb_flags=0, nb_address='0.0.0.0'): 

607 netbios_name = nbname.upper() 

608 qn_label = encode_name(netbios_name, qtype, scope) 

609 

610 p = NAME_REGISTRATION_REQUEST() 

611 p['NAME_TRN_ID'] = rand.randint(1, 32000) 

612 p['QUESTION_NAME'] = qn_label[:-1] + b'\x00' 

613 p['RR_NAME'] = qn_label[:-1] + b'\x00' 

614 p['TTL'] = 0xffff 

615 p['NB_FLAGS'] = nb_flags 

616 p['NB_ADDRESS'] = socket.inet_aton(nb_address) 

617 if not destaddr: 617 ↛ 618line 617 didn't jump to line 618, because the condition on line 617 was never true

618 p['FLAGS'] |= NM_FLAGS_BROADCAST 

619 destaddr = self.__broadcastaddr 

620 

621 res = self.send(p, destaddr, 1) 

622 return res 

623 

624 def name_query_request(self, nbname, destaddr = None, qtype = TYPE_SERVER, scope = None, timeout = 1): 

625 netbios_name = nbname.upper() 

626 qn_label = encode_name(netbios_name, qtype, scope) 

627 

628 p = NAME_QUERY_REQUEST() 

629 p['NAME_TRN_ID'] = rand.randint(1, 32000) 

630 p['QUESTION_NAME'] = qn_label[:-1] + b'\x00' 

631 p['FLAGS'] = NM_FLAGS_RD 

632 if not destaddr: 632 ↛ 633line 632 didn't jump to line 633, because the condition on line 632 was never true

633 p['FLAGS'] |= NM_FLAGS_BROADCAST 

634 

635 destaddr = self.__broadcastaddr 

636 

637 res = self.send(p, destaddr, timeout) 

638 return NBPositiveNameQueryResponse(res['ANSWERS']) 

639 

640 def node_status_request(self, nbname, destaddr, type, scope, timeout): 

641 netbios_name = nbname.upper() 

642 qn_label = encode_name(netbios_name, type, scope) 

643 p = NODE_STATUS_REQUEST() 

644 p['NAME_TRN_ID'] = rand.randint(1, 32000) 

645 p['QUESTION_NAME'] = qn_label[:-1] + b'\x00' 

646 

647 if not destaddr: 647 ↛ 648line 647 didn't jump to line 648, because the condition on line 647 was never true

648 p['FLAGS'] = NM_FLAGS_BROADCAST 

649 destaddr = self.__broadcastaddr 

650 

651 res = self.send(p, destaddr, timeout) 

652 answ = NBNodeStatusResponse(res['ANSWERS']) 

653 self.mac = answ.get_mac() 

654 return answ.entries 

655 

656################################################################################ 

657# 4.2 SESSION SERVICE PACKETS 

658################################################################################ 

659 

660class NetBIOSSessionPacket: 

661 def __init__(self, data=0): 

662 self.type = 0x0 

663 self.flags = 0x0 

664 self.length = 0x0 

665 if data == 0: 

666 self._trailer = b'' 

667 else: 

668 try: 

669 self.type = indexbytes(data,0) 

670 if self.type == NETBIOS_SESSION_MESSAGE: 

671 self.length = indexbytes(data,1) << 16 | (unpack('!H', data[2:4])[0]) 

672 else: 

673 self.flags = data[1] 

674 self.length = unpack('!H', data[2:4])[0] 

675 

676 self._trailer = data[4:] 

677 except: 

678 raise NetBIOSError('Wrong packet format ') 

679 

680 def set_type(self, type): 

681 self.type = type 

682 

683 def get_type(self): 

684 return self.type 

685 

686 def rawData(self): 

687 if self.type == NETBIOS_SESSION_MESSAGE: 

688 data = pack('!BBH', self.type, self.length >> 16, self.length & 0xFFFF) + self._trailer 

689 else: 

690 data = pack('!BBH', self.type, self.flags, self.length) + self._trailer 

691 return data 

692 

693 def set_trailer(self, data): 

694 self._trailer = data 

695 self.length = len(data) 

696 

697 def get_length(self): 

698 return self.length 

699 

700 def get_trailer(self): 

701 return self._trailer 

702 

703class NetBIOSSession: 

704 def __init__(self, myname, remote_name, remote_host, remote_type=TYPE_SERVER, sess_port=NETBIOS_SESSION_PORT, 

705 timeout=None, local_type=TYPE_WORKSTATION, sock=None): 

706 """ 

707 

708 :param unicode myname: My local NetBIOS name 

709 :param unicode remote_name: Remote NetBIOS name 

710 :param unicode remote_host: Remote IP Address 

711 :param integer remote_type: NetBIOS Host type 

712 :param integer sess_port: Session port to connect (139,445) 

713 :param integer timeout: Timeout for connection 

714 :param integer local_type: My Local Host Type 

715 :param socket sock: Socket for already established connection 

716 """ 

717 if len(myname) > 15: 717 ↛ 718line 717 didn't jump to line 718, because the condition on line 717 was never true

718 self.__myname = myname[:15].upper() 

719 else: 

720 self.__myname = myname.upper() 

721 self.__local_type = local_type 

722 

723 assert remote_name 

724 # if destination port SMB_SESSION_PORT and remote name *SMBSERVER, we're changing it to its IP address 

725 # helping solving the client mistake ;) 

726 if remote_name == '*SMBSERVER' and sess_port == SMB_SESSION_PORT: 726 ↛ 727line 726 didn't jump to line 727, because the condition on line 726 was never true

727 remote_name = remote_host 

728 

729 # If remote name is *SMBSERVER let's try to query its name.. if can't be guessed, continue and hope for the best 

730 

731 if remote_name == '*SMBSERVER': 731 ↛ 732line 731 didn't jump to line 732, because the condition on line 731 was never true

732 nb = NetBIOS() 

733 try: 

734 res = nb.getnetbiosname(remote_host) 

735 except: 

736 res = None 

737 pass 

738 

739 if res is not None: 

740 remote_name = res 

741 

742 if len(remote_name) > 15: 742 ↛ 743line 742 didn't jump to line 743, because the condition on line 742 was never true

743 self.__remote_name = remote_name[:15].upper() 

744 else: 

745 self.__remote_name = remote_name.upper() 

746 self.__remote_type = remote_type 

747 self.__remote_host = remote_host 

748 

749 if sock is not None: 749 ↛ 751line 749 didn't jump to line 751, because the condition on line 749 was never true

750 # We are acting as a server 

751 self._sock = sock 

752 else: 

753 self._sock = self._setup_connection((remote_host, sess_port), timeout) 

754 

755 if sess_port == NETBIOS_SESSION_PORT: 

756 self._request_session(remote_type, local_type, timeout) 

757 

758 def _request_session(self, remote_type, local_type, timeout): 

759 raise NotImplementedError('Not Implemented!') 

760 

761 def _setup_connection(self, peer, timeout=None): 

762 raise NotImplementedError('Not Implemented!') 

763 

764 def get_myname(self): 

765 return self.__myname 

766 

767 def get_mytype(self): 

768 return self.__local_type 

769 

770 def get_remote_host(self): 

771 return self.__remote_host 

772 

773 def get_remote_name(self): 

774 return self.__remote_name 

775 

776 def get_remote_type(self): 

777 return self.__remote_type 

778 

779 def close(self): 

780 self._sock.close() 

781 

782 def get_socket(self): 

783 return self._sock 

784 

785class NetBIOSUDPSessionPacket(Structure): 

786 TYPE_DIRECT_UNIQUE = 16 

787 TYPE_DIRECT_GROUP = 17 

788 

789 FLAGS_MORE_FRAGMENTS = 1 

790 FLAGS_FIRST_FRAGMENT = 2 

791 FLAGS_B_NODE = 0 

792 

793 structure = ( 

794 ('Type','B=16'), # Direct Unique Datagram 

795 ('Flags','B=2'), # FLAGS_FIRST_FRAGMENT 

796 ('ID','<H'), 

797 ('_SourceIP','>L'), 

798 ('SourceIP','"'), 

799 ('SourcePort','>H=138'), 

800 ('DataLegth','>H-Data'), 

801 ('Offset','>H=0'), 

802 ('SourceName','z'), 

803 ('DestinationName','z'), 

804 ('Data',':'), 

805 ) 

806 

807 def getData(self): 

808 addr = self['SourceIP'].split('.') 

809 addr = [int(x) for x in addr] 

810 addr = (((addr[0] << 8) + addr[1] << 8) + addr[2] << 8) + addr[3] 

811 self['_SourceIP'] = addr 

812 return Structure.getData(self) 

813 

814 def get_trailer(self): 

815 return self['Data'] 

816 

817class NetBIOSUDPSession(NetBIOSSession): 

818 def _setup_connection(self, peer, timeout=None): 

819 af, socktype, proto, canonname, sa = socket.getaddrinfo(peer[0], peer[1], 0, socket.SOCK_DGRAM)[0] 

820 sock = socket.socket(af, socktype, proto) 

821 sock.connect(sa) 

822 

823 sock = socket.socket(af, socktype, proto) 

824 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 

825 sock.bind((INADDR_ANY, 138)) 

826 self.peer = peer 

827 return sock 

828 

829 def _request_session(self, remote_type, local_type, timeout = None): 

830 pass 

831 

832 def next_id(self): 

833 if hasattr(self, '__dgram_id'): 

834 answer = self.__dgram_id 

835 else: 

836 self.__dgram_id = rand.randint(1,65535) 

837 answer = self.__dgram_id 

838 self.__dgram_id += 1 

839 return answer 

840 

841 def send_packet(self, data): 

842 # Yes... I know... 

843 self._sock.connect(self.peer) 

844 

845 p = NetBIOSUDPSessionPacket() 

846 p['ID'] = self.next_id() 

847 p['SourceIP'] = self._sock.getsockname()[0] 

848 p['SourceName'] = encode_name(self.get_myname(), self.get_mytype(), '')[:-1] 

849 p['DestinationName'] = encode_name(self.get_remote_name(), self.get_remote_type(), '')[:-1] 

850 p['Data'] = data 

851 

852 self._sock.sendto(str(p), self.peer) 

853 self._sock.close() 

854 

855 self._sock = self._setup_connection(self.peer) 

856 

857 def recv_packet(self, timeout = None): 

858 # The next loop is a workaround for a bigger problem: 

859 # When data reaches higher layers, the lower headers are lost, 

860 # and with them, for example, the source IP. Hence, SMB users 

861 # can't know where packets are coming from... we need a better 

862 # solution, right now, we will filter everything except packets 

863 # coming from the remote_host specified in __init__() 

864 

865 while 1: 

866 data, peer = self._sock.recvfrom(8192) 

867# print "peer: %r self.peer: %r" % (peer, self.peer) 

868 if peer == self.peer: 

869 break 

870 

871 return NetBIOSUDPSessionPacket(data) 

872 

873class NetBIOSTCPSession(NetBIOSSession): 

874 def __init__(self, myname, remote_name, remote_host, remote_type=TYPE_SERVER, sess_port=NETBIOS_SESSION_PORT, 

875 timeout=None, local_type=TYPE_WORKSTATION, sock=None, select_poll=False): 

876 """ 

877  

878 :param unicode myname: My local NetBIOS name 

879 :param unicode remote_name: Remote NetBIOS name 

880 :param unicode remote_host: Remote IP Address 

881 :param integer remote_type: NetBIOS Host type 

882 :param integer sess_port: Session port to connect (139,445) 

883 :param integer timeout: Timeout for connection 

884 :param integer local_type: My Local Host Type 

885 :param socket sock: Socket for already established connection 

886 :param boolean select_poll: Type of polling mechanism 

887 """ 

888 self.__select_poll = select_poll 

889 if self.__select_poll: 889 ↛ 890line 889 didn't jump to line 890, because the condition on line 889 was never true

890 self.read_function = self.polling_read 

891 else: 

892 self.read_function = self.non_polling_read 

893 NetBIOSSession.__init__(self, myname, remote_name, remote_host, remote_type=remote_type, sess_port=sess_port, 

894 timeout=timeout, local_type=local_type, sock=sock) 

895 

896 def _setup_connection(self, peer, timeout=None): 

897 try: 

898 af, socktype, proto, canonname, sa = socket.getaddrinfo(peer[0], peer[1], 0, socket.SOCK_STREAM)[0] 

899 sock = socket.socket(af, socktype, proto) 

900 oldtimeout = sock.gettimeout() 

901 sock.settimeout(timeout) 

902 sock.connect(sa) 

903 sock.settimeout(oldtimeout) 

904 except socket.error as e: 

905 raise socket.error("Connection error (%s:%s)" % (peer[0], peer[1]), e) 

906 return sock 

907 

908 def send_packet(self, data): 

909 p = NetBIOSSessionPacket() 

910 p.set_type(NETBIOS_SESSION_MESSAGE) 

911 p.set_trailer(data) 

912 self._sock.sendall(p.rawData()) 

913 

914 def recv_packet(self, timeout = None): 

915 data = self.__read(timeout) 

916 NBSPacket = NetBIOSSessionPacket(data) 

917 if NBSPacket.get_type() == NETBIOS_SESSION_KEEP_ALIVE: 917 ↛ 919line 917 didn't jump to line 919, because the condition on line 917 was never true

918 # Discard packet 

919 return self.recv_packet(timeout) 

920 return NetBIOSSessionPacket(data) 

921 

922 def _request_session(self, remote_type, local_type, timeout = None): 

923 p = NetBIOSSessionPacket() 

924 remote_name = encode_name(self.get_remote_name(), remote_type, '') 

925 myname = encode_name(self.get_myname(), local_type, '') 

926 p.set_type(NETBIOS_SESSION_REQUEST) 

927 p.set_trailer(remote_name + myname) 

928 

929 self._sock.sendall(p.rawData()) 

930 while 1: 

931 p = self.recv_packet(timeout) 

932 if p.get_type() == NETBIOS_SESSION_NEGATIVE_RESPONSE: 932 ↛ 933line 932 didn't jump to line 933, because the condition on line 932 was never true

933 raise NetBIOSError('Cannot request session (Called Name:%s)' % self.get_remote_name()) 

934 elif p.get_type() == NETBIOS_SESSION_POSITIVE_RESPONSE: 934 ↛ 938line 934 didn't jump to line 938, because the condition on line 934 was never false

935 break 

936 else: 

937 # Ignore all other messages, most probably keepalive messages 

938 pass 

939 

940 def polling_read(self, read_length, timeout): 

941 data = b'' 

942 if timeout is None: 

943 timeout = 3600 

944 

945 time_left = timeout 

946 CHUNK_TIME = 0.025 

947 bytes_left = read_length 

948 

949 while bytes_left > 0: 

950 try: 

951 ready, _, _ = select.select([self._sock.fileno()], [], [], 0) 

952 

953 if not ready: 

954 if time_left <= 0: 

955 raise NetBIOSTimeout 

956 else: 

957 time.sleep(CHUNK_TIME) 

958 time_left -= CHUNK_TIME 

959 continue 

960 

961 received = self._sock.recv(bytes_left) 

962 if len(received) == 0: 

963 raise NetBIOSError('Error while reading from remote', ERRCLASS_OS, None) 

964 

965 data = data + received 

966 bytes_left = read_length - len(data) 

967 except select.error as ex: 

968 if ex.errno != errno.EINTR and ex.errno != errno.EAGAIN: 

969 raise NetBIOSError('Error occurs while reading from remote', ERRCLASS_OS, ex.errno) 

970 

971 return bytes(data) 

972 

973 def non_polling_read(self, read_length, timeout): 

974 data = b'' 

975 if timeout is None: 975 ↛ 976line 975 didn't jump to line 976, because the condition on line 975 was never true

976 timeout = 3600 

977 

978 start_time = time.time() 

979 bytes_left = read_length 

980 

981 while bytes_left > 0: 

982 self._sock.settimeout(timeout) 

983 try: 

984 received = self._sock.recv(bytes_left) 

985 except socket.timeout: 

986 raise NetBIOSTimeout 

987 except Exception as ex: 

988 raise NetBIOSError('Error occurs while reading from remote', ERRCLASS_OS, ex.errno) 

989 

990 if (time.time() - start_time) > timeout: 990 ↛ 991line 990 didn't jump to line 991, because the condition on line 990 was never true

991 raise NetBIOSTimeout 

992 

993 if len(received) == 0: 993 ↛ 994line 993 didn't jump to line 994, because the condition on line 993 was never true

994 raise NetBIOSError('Error while reading from remote', ERRCLASS_OS, None) 

995 

996 data = data + received 

997 bytes_left = read_length - len(data) 

998 

999 return bytes(data) 

1000 

1001 def __read(self, timeout = None): 

1002 data = self.read_function(4, timeout) 

1003 type, flags, length = unpack('>ccH', data) 

1004 if ord(type) == NETBIOS_SESSION_MESSAGE: 

1005 length |= ord(flags) << 16 

1006 else: 

1007 if ord(flags) & 0x01: 1007 ↛ 1008line 1007 didn't jump to line 1008, because the condition on line 1007 was never true

1008 length |= 0x10000 

1009 data2 = self.read_function(length, timeout) 

1010 

1011 return data + data2