nmb.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982
  1. from __future__ import print_function
  2. from __future__ import absolute_import
  3. # Copyright (c) 2003-2016 CORE Security Technologies
  4. #
  5. # This software is provided under under a slightly modified version
  6. # of the Apache Software License. See the accompanying LICENSE file
  7. # for more information.
  8. #
  9. # -*- mode: python; tab-width: 4 -*-
  10. #
  11. # Copyright (C) 2001 Michael Teo <michaelteo@bigfoot.com>
  12. # nmb.py - NetBIOS library
  13. #
  14. # This software is provided 'as-is', without any express or implied warranty.
  15. # In no event will the author be held liable for any damages arising from the
  16. # use of this software.
  17. #
  18. # Permission is granted to anyone to use this software for any purpose,
  19. # including commercial applications, and to alter it and redistribute it
  20. # freely, subject to the following restrictions:
  21. #
  22. # 1. The origin of this software must not be misrepresented; you must not
  23. # claim that you wrote the original software. If you use this software
  24. # in a product, an acknowledgment in the product documentation would be
  25. # appreciated but is not required.
  26. #
  27. # 2. Altered source versions must be plainly marked as such, and must not be
  28. # misrepresented as being the original software.
  29. #
  30. # 3. This notice cannot be removed or altered from any source distribution.
  31. #
  32. # Altered source done by Alberto Solino (@agsolino)
  33. import socket
  34. import string
  35. import re
  36. import select
  37. import errno
  38. from random import randint
  39. from struct import pack, unpack
  40. import time
  41. from .structure import Structure
  42. CVS_REVISION = '$Revision: 526 $'
  43. # Taken from socket module reference
  44. INADDR_ANY = '0.0.0.0'
  45. BROADCAST_ADDR = '<broadcast>'
  46. # Default port for NetBIOS name service
  47. NETBIOS_NS_PORT = 137
  48. # Default port for NetBIOS session service
  49. NETBIOS_SESSION_PORT = 139
  50. # Default port for SMB session service
  51. SMB_SESSION_PORT = 445
  52. # Owner Node Type Constants
  53. NODE_B = 0x0000
  54. NODE_P = 0x2000
  55. NODE_M = 0x4000
  56. NODE_RESERVED = 0x6000
  57. NODE_GROUP = 0x8000
  58. NODE_UNIQUE = 0x0
  59. # Name Type Constants
  60. TYPE_UNKNOWN = 0x01
  61. TYPE_WORKSTATION = 0x00
  62. TYPE_CLIENT = 0x03
  63. TYPE_SERVER = 0x20
  64. TYPE_DOMAIN_MASTER = 0x1B
  65. TYPE_DOMAIN_CONTROLLER = 0x1C
  66. TYPE_MASTER_BROWSER = 0x1D
  67. TYPE_BROWSER = 0x1E
  68. TYPE_NETDDE = 0x1F
  69. TYPE_STATUS = 0x21
  70. # Opcodes values
  71. OPCODE_QUERY = 0
  72. OPCODE_REGISTRATION = 0x5
  73. OPCODE_RELEASE = 0x6
  74. OPCODE_WACK = 0x7
  75. OPCODE_REFRESH = 0x8
  76. OPCODE_REQUEST = 0
  77. OPCODE_RESPONSE = 0x10
  78. # NM_FLAGS
  79. NM_FLAGS_BROADCAST = 0x1
  80. NM_FLAGS_UNICAST = 0
  81. NM_FLAGS_RA = 0x8
  82. NM_FLAGS_RD = 0x10
  83. NM_FLAGS_TC = 0x20
  84. NM_FLAGS_AA = 0x40
  85. # QUESTION_TYPE
  86. QUESTION_TYPE_NB = 0x20 # NetBIOS general Name Service Resource Record
  87. QUESTION_TYPE_NBSTAT = 0x21 # NetBIOS NODE STATUS Resource Record
  88. # QUESTION_CLASS
  89. QUESTION_CLASS_IN = 0x1 # Internet class
  90. # RR_TYPE Resource Record Type code
  91. RR_TYPE_A = 0x1 # IP address Resource Record
  92. RR_TYPE_NS = 0x2 # Name Server Resource Record
  93. RR_TYPE_NULL = 0xA # NULL Resource Record
  94. RR_TYPE_NB = 0x20 # NetBIOS general Name Service Resource Record
  95. RR_TYPE_NBSTAT = 0x21 # NetBIOS NODE STATUS Resource Record
  96. # Resource Record Class
  97. RR_CLASS_IN = 1 # Internet class
  98. # RCODE values
  99. RCODE_FMT_ERR = 0x1 # Format Error. Request was invalidly formatted.
  100. RCODE_SRV_ERR = 0x2 # Server failure. Problem with NBNS, cannot process name.
  101. RCODE_IMP_ERR = 0x4 # Unsupported request error. Allowable only for challenging NBNS when gets an Update type
  102. # registration request.
  103. RCODE_RFS_ERR = 0x5 # Refused error. For policy reasons server will not register this name from this host.
  104. RCODE_ACT_ERR = 0x6 # Active error. Name is owned by another node.
  105. RCODE_CFT_ERR = 0x7 # Name in conflict error. A UNIQUE name is owned by more than one node.
  106. # NAME_FLAGS
  107. NAME_FLAGS_PRM = 0x0200 # Permanent Name Flag. If one (1) then entry is for the permanent node name. Flag is zero
  108. # (0) for all other names.
  109. NAME_FLAGS_ACT = 0x0400 # Active Name Flag. All entries have this flag set to one (1).
  110. NAME_FLAG_CNF = 0x0800 # Conflict Flag. If one (1) then name on this node is in conflict.
  111. NAME_FLAG_DRG = 0x1000 # Deregister Flag. If one (1) then this name is in the process of being deleted.
  112. NAME_TYPES = { TYPE_UNKNOWN: 'Unknown', TYPE_WORKSTATION: 'Workstation', TYPE_CLIENT: 'Client',
  113. TYPE_SERVER: 'Server', TYPE_MASTER_BROWSER: 'Master Browser', TYPE_BROWSER: 'Browser Server',
  114. TYPE_DOMAIN_MASTER: 'Domain Master' , TYPE_NETDDE: 'NetDDE Server'}
  115. # NetBIOS Session Types
  116. NETBIOS_SESSION_MESSAGE = 0x0
  117. NETBIOS_SESSION_REQUEST = 0x81
  118. NETBIOS_SESSION_POSITIVE_RESPONSE = 0x82
  119. NETBIOS_SESSION_NEGATIVE_RESPONSE = 0x83
  120. NETBIOS_SESSION_RETARGET_RESPONSE = 0x84
  121. NETBIOS_SESSION_KEEP_ALIVE = 0x85
  122. def strerror(errclass, errcode):
  123. if errclass == ERRCLASS_OS:
  124. return 'OS Error', str(errcode)
  125. elif errclass == ERRCLASS_QUERY:
  126. return 'Query Error', QUERY_ERRORS.get(errcode, 'Unknown error')
  127. elif errclass == ERRCLASS_SESSION:
  128. return 'Session Error', SESSION_ERRORS.get(errcode, 'Unknown error')
  129. else:
  130. return 'Unknown Error Class', 'Unknown Error'
  131. class NetBIOSError(Exception): pass
  132. class NetBIOSTimeout(Exception):
  133. def __init__(self, message = 'The NETBIOS connection with the remote host timed out.'):
  134. Exception.__init__(self, message)
  135. class NBResourceRecord:
  136. def __init__(self, data = 0):
  137. self._data = data
  138. try:
  139. if self._data:
  140. self.rr_name = (re.split('\x00',data))[0]
  141. offset = len(self.rr_name)+1
  142. self.rr_type = unpack('>H', self._data[offset:offset+2])[0]
  143. self.rr_class = unpack('>H', self._data[offset+2: offset+4])[0]
  144. self.ttl = unpack('>L',self._data[offset+4:offset+8])[0]
  145. self.rdlength = unpack('>H', self._data[offset+8:offset+10])[0]
  146. self.rdata = self._data[offset+10:offset+10+self.rdlength]
  147. offset = self.rdlength - 2
  148. self.unit_id = data[offset:offset+6]
  149. else:
  150. self.rr_name = ''
  151. self.rr_type = 0
  152. self.rr_class = 0
  153. self.ttl = 0
  154. self.rdlength = 0
  155. self.rdata = ''
  156. self.unit_id = ''
  157. except Exception:
  158. raise NetBIOSError( 'Wrong packet format ' )
  159. def set_rr_name(self, name):
  160. self.rr_name = name
  161. def set_rr_type(self, name):
  162. self.rr_type = name
  163. def set_rr_class(self,cl):
  164. self.rr_class = cl
  165. def set_ttl(self,ttl):
  166. self.ttl = ttl
  167. def set_rdata(self,rdata):
  168. self.rdata = rdata
  169. self.rdlength = len(rdata)
  170. def get_unit_id(self):
  171. return self.unit_id
  172. def get_rr_name(self):
  173. return self.rr_name
  174. def get_rr_class(self):
  175. return self.rr_class
  176. def get_ttl(self):
  177. return self.ttl
  178. def get_rdlength(self):
  179. return self.rdlength
  180. def get_rdata(self):
  181. return self.rdata
  182. def rawData(self):
  183. return self.rr_name + pack('!HHLH',self.rr_type, self.rr_class, self.ttl, self.rdlength) + self.rdata
  184. class NBNodeStatusResponse(NBResourceRecord):
  185. def __init__(self, data = 0):
  186. NBResourceRecord.__init__(self,data)
  187. self.num_names = 0
  188. self.node_names = [ ]
  189. self.statstics = ''
  190. self.mac = '00-00-00-00-00-00'
  191. try:
  192. if data:
  193. self._data = self.get_rdata()
  194. self.num_names = unpack('>B',self._data[:1])[0]
  195. offset = 1
  196. for i in range(0, self.num_names):
  197. name = self._data[offset:offset + 15]
  198. type,flags = unpack('>BH', self._data[offset + 15: offset + 18])
  199. offset += 18
  200. self.node_names.append(NBNodeEntry(name, type ,flags))
  201. self.set_mac_in_hexa(self.get_unit_id())
  202. except Exception:
  203. raise NetBIOSError( 'Wrong packet format ' )
  204. def set_mac_in_hexa(self, data):
  205. data_aux = ''
  206. for d in data:
  207. if data_aux == '':
  208. data_aux = '%02x' % ord(d)
  209. else:
  210. data_aux += '-%02x' % ord(d)
  211. self.mac = string.upper(data_aux)
  212. def get_num_names(self):
  213. return self.num_names
  214. def get_mac(self):
  215. return self.mac
  216. def set_num_names(self, num):
  217. self.num_names = num
  218. def get_node_names(self):
  219. return self.node_names
  220. def add_node_name(self,node_names):
  221. self.node_names.append(node_names)
  222. self.num_names += 1
  223. def rawData(self):
  224. res = pack('!B', self.num_names )
  225. for i in range(0, self.num_names):
  226. res += self.node_names[i].rawData()
  227. class NBPositiveNameQueryResponse(NBResourceRecord):
  228. def __init__(self, data = 0):
  229. NBResourceRecord.__init__(self, data)
  230. self.addr_entries = [ ]
  231. if data:
  232. self._data = self.get_rdata()
  233. _qn_length, qn_name, qn_scope = decode_name(data)
  234. self._netbios_name = string.rstrip(qn_name[:-1]) + qn_scope
  235. self._name_type = ord(qn_name[-1])
  236. self._nb_flags = unpack('!H', self._data[:2])
  237. offset = 2
  238. while offset<len(self._data):
  239. self.addr_entries.append('%d.%d.%d.%d' % unpack('4B', (self._data[offset:offset+4])))
  240. offset += 4
  241. def get_netbios_name(self):
  242. return self._netbios_name
  243. def get_name_type(self):
  244. return self._name_type
  245. def get_addr_entries(self):
  246. return self.addr_entries
  247. class NetBIOSPacket:
  248. """ This is a packet as defined in RFC 1002 """
  249. def __init__(self, data = 0):
  250. self.name_trn_id = 0x0 # Transaction ID for Name Service Transaction.
  251. # Requestor places a unique value for each active
  252. # transaction. Responder puts NAME_TRN_ID value
  253. # from request packet in response packet.
  254. self.opcode = 0 # Packet type code
  255. self.nm_flags = 0 # Flags for operation
  256. self.rcode = 0 # Result codes of request.
  257. self.qdcount = 0 # Unsigned 16 bit integer specifying the number of entries in the question section of a Name
  258. self.ancount = 0 # Unsigned 16 bit integer specifying the number of
  259. # resource records in the answer section of a Name
  260. # Service packet.
  261. self.nscount = 0 # Unsigned 16 bit integer specifying the number of
  262. # resource records in the authority section of a
  263. # Name Service packet.
  264. self.arcount = 0 # Unsigned 16 bit integer specifying the number of
  265. # resource records in the additional records
  266. # section of a Name Service packeT.
  267. self.questions = ''
  268. self.answers = ''
  269. if data == 0:
  270. self._data = ''
  271. else:
  272. try:
  273. self._data = data
  274. self.opcode = ord(data[2]) >> 3
  275. self.nm_flags = ((ord(data[2]) & 0x3) << 4) | ((ord(data[3]) & 0xf0) >> 4)
  276. self.name_trn_id = unpack('>H', self._data[:2])[0]
  277. self.rcode = ord(data[3]) & 0x0f
  278. self.qdcount = unpack('>H', self._data[4:6])[0]
  279. self.ancount = unpack('>H', self._data[6:8])[0]
  280. self.nscount = unpack('>H', self._data[8:10])[0]
  281. self.arcount = unpack('>H', self._data[10:12])[0]
  282. self.answers = self._data[12:]
  283. except Exception:
  284. raise NetBIOSError( 'Wrong packet format ' )
  285. def set_opcode(self, opcode):
  286. self.opcode = opcode
  287. def set_trn_id(self, trn):
  288. self.name_trn_id = trn
  289. def set_nm_flags(self, nm_flags):
  290. self.nm_flags = nm_flags
  291. def set_rcode(self, rcode):
  292. self.rcode = rcode
  293. def addQuestion(self, question, qtype, qclass):
  294. self.qdcount += 1
  295. self.questions += question + pack('!HH',qtype,qclass)
  296. def get_trn_id(self):
  297. return self.name_trn_id
  298. def get_rcode(self):
  299. return self.rcode
  300. def get_nm_flags(self):
  301. return self.nm_flags
  302. def get_opcode(self):
  303. return self.opcode
  304. def get_qdcount(self):
  305. return self.qdcount
  306. def get_ancount(self):
  307. return self.ancount
  308. def get_nscount(self):
  309. return self.nscount
  310. def get_arcount(self):
  311. return self.arcount
  312. def rawData(self):
  313. secondWord = self.opcode << 11
  314. secondWord |= self.nm_flags << 4
  315. secondWord |= self.rcode
  316. data = pack('!HHHHHH', self.name_trn_id, secondWord , self.qdcount, self.ancount, self.nscount, self.arcount) + self.questions + self.answers
  317. return data
  318. def get_answers(self):
  319. return self.answers
  320. class NBHostEntry:
  321. def __init__(self, nbname, nametype, ip):
  322. self.__nbname = nbname
  323. self.__nametype = nametype
  324. self.__ip = ip
  325. def get_nbname(self):
  326. return self.__nbname
  327. def get_nametype(self):
  328. return self.__nametype
  329. def get_ip(self):
  330. return self.__ip
  331. def __repr__(self):
  332. return '<NBHostEntry instance: NBname="' + self.__nbname + '", IP="' + self.__ip + '">'
  333. class NBNodeEntry:
  334. def __init__(self, nbname, nametype, flags):
  335. self.__nbname = string.ljust(nbname,17)
  336. self.__nametype = nametype
  337. self.__flags = flags
  338. self.__isgroup = flags & 0x8000
  339. self.__nodetype = flags & 0x6000
  340. self.__deleting = flags & 0x1000
  341. self.__isconflict = flags & 0x0800
  342. self.__isactive = flags & 0x0400
  343. self.__ispermanent = flags & 0x0200
  344. def get_nbname(self):
  345. return self.__nbname
  346. def get_nametype(self):
  347. return self.__nametype
  348. def is_group(self):
  349. return self.__isgroup
  350. def get_nodetype(self):
  351. return self.__nodetype
  352. def is_deleting(self):
  353. return self.__deleting
  354. def is_conflict(self):
  355. return self.__isconflict
  356. def is_active(self):
  357. return self.__isactive
  358. def is_permanent(self):
  359. return self.__ispermanent
  360. def set_nbname(self, name):
  361. self.__nbname = string.ljust(name,17)
  362. def set_nametype(self, type):
  363. self.__nametype = type
  364. def set_flags(self,flags):
  365. self.__flags = flags
  366. def __repr__(self):
  367. s = '<NBNodeEntry instance: NBname="' + self.__nbname + '" NameType="' + NAME_TYPES[self.__nametype] + '"'
  368. if self.__isactive:
  369. s += ' ACTIVE'
  370. if self.__isgroup:
  371. s += ' GROUP'
  372. if self.__isconflict:
  373. s += ' CONFLICT'
  374. if self.__deleting:
  375. s += ' DELETING'
  376. return s
  377. def rawData(self):
  378. return self.__nbname + pack('!BH',self.__nametype, self.__flags)
  379. class NetBIOS:
  380. # Creates a NetBIOS instance without specifying any default NetBIOS domain nameserver.
  381. # All queries will be sent through the servport.
  382. def __init__(self, servport = NETBIOS_NS_PORT):
  383. self.__servport = NETBIOS_NS_PORT
  384. self.__nameserver = None
  385. self.__broadcastaddr = BROADCAST_ADDR
  386. self.mac = '00-00-00-00-00-00'
  387. def _setup_connection(self, dstaddr):
  388. port = randint(10000, 60000)
  389. af, socktype, proto, _canonname, _sa = socket.getaddrinfo(dstaddr, port, socket.AF_INET, socket.SOCK_DGRAM)[0]
  390. s = socket.socket(af, socktype, proto)
  391. has_bind = 1
  392. for _i in range(0, 10):
  393. # We try to bind to a port for 10 tries
  394. try:
  395. s.bind(( INADDR_ANY, randint(10000, 60000) ))
  396. s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
  397. has_bind = 1
  398. except socket.error:
  399. pass
  400. if not has_bind:
  401. raise NetBIOSError( 'Cannot bind to a good UDP port', ERRCLASS_OS, errno.EAGAIN)
  402. self.__sock = s
  403. # Set the default NetBIOS domain nameserver.
  404. def set_nameserver(self, nameserver):
  405. self.__nameserver = nameserver
  406. # Return the default NetBIOS domain nameserver, or None if none is specified.
  407. def get_nameserver(self):
  408. return self.__nameserver
  409. # Set the broadcast address to be used for query.
  410. def set_broadcastaddr(self, broadcastaddr):
  411. self.__broadcastaddr = broadcastaddr
  412. # Return the broadcast address to be used, or BROADCAST_ADDR if default broadcast address is used.
  413. def get_broadcastaddr(self):
  414. return self.__broadcastaddr
  415. # Returns a NBPositiveNameQueryResponse instance containing the host information for nbname.
  416. # If a NetBIOS domain nameserver has been specified, it will be used for the query.
  417. # Otherwise, the query is broadcasted on the broadcast address.
  418. def gethostbyname(self, nbname, qtype = TYPE_WORKSTATION, scope = None, timeout = 1):
  419. return self.__queryname(nbname, self.__nameserver, qtype, scope, timeout)
  420. # Returns a list of NBNodeEntry instances containing node status information for nbname.
  421. # If destaddr contains an IP address, then this will become an unicast query on the destaddr.
  422. # Raises NetBIOSTimeout if timeout (in secs) is reached.
  423. # Raises NetBIOSError for other errors
  424. def getnodestatus(self, nbname, destaddr = None, type = TYPE_WORKSTATION, scope = None, timeout = 1):
  425. if destaddr:
  426. return self.__querynodestatus(nbname, destaddr, type, scope, timeout)
  427. else:
  428. return self.__querynodestatus(nbname, self.__nameserver, type, scope, timeout)
  429. def getnetbiosname(self, ip):
  430. entries = self.getnodestatus('*',ip)
  431. entries = filter(lambda x:x.get_nametype() == TYPE_SERVER, entries)
  432. return entries[0].get_nbname().strip()
  433. def getmacaddress(self):
  434. return self.mac
  435. def __queryname(self, nbname, destaddr, qtype, scope, timeout, retries = 0):
  436. self._setup_connection(destaddr)
  437. trn_id = randint(1, 32000)
  438. p = NetBIOSPacket()
  439. p.set_trn_id(trn_id)
  440. netbios_name = nbname.upper()
  441. qn_label = encode_name(netbios_name, qtype, scope)
  442. p.addQuestion(qn_label, QUESTION_TYPE_NB, QUESTION_CLASS_IN)
  443. p.set_nm_flags(NM_FLAGS_RD)
  444. if not destaddr:
  445. p.set_nm_flags(p.get_nm_flags() | NM_FLAGS_BROADCAST)
  446. destaddr = self.__broadcastaddr
  447. req = p.rawData()
  448. tries = retries
  449. while 1:
  450. self.__sock.sendto(req, ( destaddr, self.__servport ))
  451. try:
  452. ready, _, _ = select.select([ self.__sock.fileno() ], [ ] , [ ], timeout)
  453. if not ready:
  454. if tries:
  455. # Retry again until tries == 0
  456. tries -= 1
  457. else:
  458. raise NetBIOSTimeout
  459. else:
  460. data, _ = self.__sock.recvfrom(65536, 0)
  461. res = NetBIOSPacket(data)
  462. if res.get_trn_id() == p.get_trn_id():
  463. if res.get_rcode():
  464. if res.get_rcode() == 0x03:
  465. return None
  466. else:
  467. raise NetBIOSError( 'Negative name query response', ERRCLASS_QUERY, res.get_rcode())
  468. if res.get_ancount() != 1:
  469. raise NetBIOSError( 'Malformed response')
  470. return NBPositiveNameQueryResponse(res.get_answers())
  471. except select.error as ex:
  472. if ex[0] != errno.EINTR and ex[0] != errno.EAGAIN:
  473. raise NetBIOSError( 'Error occurs while waiting for response', ERRCLASS_OS, ex[0])
  474. raise
  475. def __querynodestatus(self, nbname, destaddr, type, scope, timeout):
  476. self._setup_connection(destaddr)
  477. trn_id = randint(1, 32000)
  478. p = NetBIOSPacket()
  479. p.set_trn_id(trn_id)
  480. netbios_name = string.upper(nbname)
  481. qn_label = encode_name(netbios_name, type, scope)
  482. p.addQuestion(qn_label, QUESTION_TYPE_NBSTAT, QUESTION_CLASS_IN)
  483. if not destaddr:
  484. p.set_nm_flags(NM_FLAGS_BROADCAST)
  485. destaddr = self.__broadcastaddr
  486. req = p.rawData()
  487. tries = 3
  488. while 1:
  489. try:
  490. self.__sock.sendto(req, 0, ( destaddr, self.__servport ))
  491. ready, _, _ = select.select([ self.__sock.fileno() ], [ ] , [ ], timeout)
  492. if not ready:
  493. if tries:
  494. # Retry again until tries == 0
  495. tries -= 1
  496. else:
  497. raise NetBIOSTimeout
  498. else:
  499. try:
  500. data, _ = self.__sock.recvfrom(65536, 0)
  501. except Exception as e:
  502. raise NetBIOSError("recvfrom error: %s" % str(e))
  503. self.__sock.close()
  504. res = NetBIOSPacket(data)
  505. if res.get_trn_id() == p.get_trn_id():
  506. if res.get_rcode():
  507. if res.get_rcode() == 0x03:
  508. # I'm just guessing here
  509. raise NetBIOSError("Cannot get data from server")
  510. else:
  511. raise NetBIOSError( 'Negative name query response', ERRCLASS_QUERY, res.get_rcode())
  512. answ = NBNodeStatusResponse(res.get_answers())
  513. self.mac = answ.get_mac()
  514. return answ.get_node_names()
  515. except select.error as ex:
  516. if ex[0] != errno.EINTR and ex[0] != errno.EAGAIN:
  517. raise NetBIOSError( 'Error occurs while waiting for response', ERRCLASS_OS, ex[0])
  518. except socket.error as ex:
  519. raise NetBIOSError('Connection error: %s' % str(ex))
  520. # Perform first and second level encoding of name as specified in RFC 1001 (Section 4)
  521. def encode_name(name, type, scope):
  522. if name == '*':
  523. name += '\0' * 15
  524. elif len(name) > 15:
  525. name = name[:15] + chr(type)
  526. else:
  527. name = string.ljust(name, 15) + chr(type)
  528. encoded_name = chr(len(name) * 2) + re.sub('.', _do_first_level_encoding, name)
  529. if scope:
  530. encoded_scope = ''
  531. for s in string.split(scope, '.'):
  532. encoded_scope = encoded_scope + chr(len(s)) + s
  533. return encoded_name + encoded_scope + '\0'
  534. else:
  535. return encoded_name + '\0'
  536. # Internal method for use in encode_name()
  537. def _do_first_level_encoding(m):
  538. s = ord(m.group(0))
  539. return string.uppercase[s >> 4] + string.uppercase[s & 0x0f]
  540. def decode_name(name):
  541. name_length = ord(name[0])
  542. assert name_length == 32
  543. decoded_name = re.sub('..', _do_first_level_decoding, name[1:33])
  544. if name[33] == '\0':
  545. return 34, decoded_name, ''
  546. else:
  547. decoded_domain = ''
  548. offset = 34
  549. while 1:
  550. domain_length = ord(name[offset])
  551. if domain_length == 0:
  552. break
  553. decoded_domain = '.' + name[offset:offset + domain_length]
  554. offset += domain_length
  555. return offset + 1, decoded_name, decoded_domain
  556. def _do_first_level_decoding(m):
  557. s = m.group(0)
  558. return chr(((ord(s[0]) - ord('A')) << 4) | (ord(s[1]) - ord('A')))
  559. class NetBIOSSessionPacket:
  560. def __init__(self, data = 0):
  561. self.type = 0x0
  562. self.flags = 0x0
  563. self.length = 0x0
  564. if data == 0:
  565. self._trailer = ''
  566. else:
  567. try:
  568. self.type = ord(data[0])
  569. if self.type == NETBIOS_SESSION_MESSAGE:
  570. self.length = ord(data[1]) << 16 | (unpack('!H', data[2:4])[0])
  571. else:
  572. self.flags = ord(data[1])
  573. self.length = unpack('!H', data[2:4])[0]
  574. self._trailer = data[4:]
  575. except:
  576. raise NetBIOSError( 'Wrong packet format ' )
  577. def set_type(self, type):
  578. self.type = type
  579. def get_type(self):
  580. return self.type
  581. def rawData(self):
  582. if self.type == NETBIOS_SESSION_MESSAGE:
  583. data = pack('!BBH',self.type,self.length >> 16,self.length & 0xFFFF) + self._trailer
  584. else:
  585. data = pack('!BBH',self.type,self.flags,self.length) + self._trailer
  586. return data
  587. def set_trailer(self,data):
  588. self._trailer = data
  589. self.length = len(data)
  590. def get_length(self):
  591. return self.length
  592. def get_trailer(self):
  593. return self._trailer
  594. class NetBIOSSession:
  595. def __init__(self, myname, remote_name, remote_host, remote_type = TYPE_SERVER, sess_port = NETBIOS_SESSION_PORT, timeout = None, local_type = TYPE_WORKSTATION, sock = None):
  596. if len(myname) > 15:
  597. self.__myname = string.upper(myname[:15])
  598. else:
  599. self.__myname = string.upper(myname)
  600. self.__local_type = local_type
  601. assert remote_name
  602. # if destination port SMB_SESSION_PORT and remote name *SMBSERVER, we're changing it to its IP address
  603. # helping solving the client mistake ;)
  604. if remote_name == '*SMBSERVER' and sess_port == SMB_SESSION_PORT:
  605. remote_name = remote_host
  606. # If remote name is *SMBSERVER let's try to query its name.. if can't be guessed, continue and hope for the best
  607. if remote_name == '*SMBSERVER':
  608. nb = NetBIOS()
  609. try:
  610. res = nb.getnetbiosname(remote_host)
  611. except:
  612. res = None
  613. pass
  614. if res is not None:
  615. remote_name = res
  616. if len(remote_name) > 15:
  617. self.__remote_name = string.upper(remote_name[:15])
  618. else:
  619. self.__remote_name = string.upper(remote_name)
  620. self.__remote_type = remote_type
  621. self.__remote_host = remote_host
  622. if sock is not None:
  623. # We are acting as a server
  624. self._sock = sock
  625. else:
  626. self._sock = self._setup_connection((remote_host, sess_port))
  627. if sess_port == NETBIOS_SESSION_PORT:
  628. self._request_session(remote_type, local_type, timeout)
  629. def get_myname(self):
  630. return self.__myname
  631. def get_mytype(self):
  632. return self.__local_type
  633. def get_remote_host(self):
  634. return self.__remote_host
  635. def get_remote_name(self):
  636. return self.__remote_name
  637. def get_remote_type(self):
  638. return self.__remote_type
  639. def close(self):
  640. self._sock.close()
  641. def get_socket(self):
  642. return self._sock
  643. class NetBIOSUDPSessionPacket(Structure):
  644. TYPE_DIRECT_UNIQUE = 16
  645. TYPE_DIRECT_GROUP = 17
  646. FLAGS_MORE_FRAGMENTS = 1
  647. FLAGS_FIRST_FRAGMENT = 2
  648. FLAGS_B_NODE = 0
  649. structure = (
  650. ('Type','B=16'), # Direct Unique Datagram
  651. ('Flags','B=2'), # FLAGS_FIRST_FRAGMENT
  652. ('ID','<H'),
  653. ('_SourceIP','>L'),
  654. ('SourceIP','"'),
  655. ('SourcePort','>H=138'),
  656. ('DataLegth','>H-Data'),
  657. ('Offset','>H=0'),
  658. ('SourceName','z'),
  659. ('DestinationName','z'),
  660. ('Data',':'),
  661. )
  662. def getData(self):
  663. addr = self['SourceIP'].split('.')
  664. addr = [int(x) for x in addr]
  665. addr = (((addr[0] << 8) + addr[1] << 8) + addr[2] << 8) + addr[3]
  666. self['_SourceIP'] = addr
  667. return Structure.getData(self)
  668. def get_trailer(self):
  669. return self['Data']
  670. class NetBIOSUDPSession(NetBIOSSession):
  671. def _setup_connection(self, peer):
  672. af, socktype, proto, canonname, sa = socket.getaddrinfo(peer[0], peer[1], 0, socket.SOCK_DGRAM)[0]
  673. sock = socket.socket(af, socktype, proto)
  674. sock.connect(sa)
  675. sock = socket.socket(af, socktype, proto)
  676. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  677. sock.bind((INADDR_ANY, 138))
  678. self.peer = peer
  679. return sock
  680. def _request_session(self, remote_type, local_type, timeout = None):
  681. pass
  682. def next_id(self):
  683. if hasattr(self, '__dgram_id'):
  684. answer = self.__dgram_id
  685. else:
  686. self.__dgram_id = randint(1,65535)
  687. answer = self.__dgram_id
  688. self.__dgram_id += 1
  689. return answer
  690. def send_packet(self, data):
  691. # Yes... I know...
  692. self._sock.connect(self.peer)
  693. p = NetBIOSUDPSessionPacket()
  694. p['ID'] = self.next_id()
  695. p['SourceIP'] = self._sock.getsockname()[0]
  696. p['SourceName'] = encode_name(self.get_myname(), self.get_mytype(), '')[:-1]
  697. p['DestinationName'] = encode_name(self.get_remote_name(), self.get_remote_type(), '')[:-1]
  698. p['Data'] = data
  699. self._sock.sendto(str(p), self.peer)
  700. self._sock.close()
  701. self._sock = self._setup_connection(self.peer)
  702. def recv_packet(self, timeout = None):
  703. # The next loop is a workaround for a bigger problem:
  704. # When data reaches higher layers, the lower headers are lost,
  705. # and with them, for example, the source IP. Hence, SMB users
  706. # can't know where packets are comming from... we need a better
  707. # solution, right now, we will filter everything except packets
  708. # coming from the remote_host specified in __init__()
  709. while 1:
  710. data, peer = self._sock.recvfrom(8192)
  711. # print "peer: %r self.peer: %r" % (peer, self.peer)
  712. if peer == self.peer: break
  713. return NetBIOSUDPSessionPacket(data)
  714. class NetBIOSTCPSession(NetBIOSSession):
  715. def __init__(self, myname, remote_name, remote_host, remote_type = TYPE_SERVER, sess_port = NETBIOS_SESSION_PORT, timeout = None, local_type = TYPE_WORKSTATION, sock = None, select_poll = False):
  716. self.__select_poll = select_poll
  717. if self.__select_poll:
  718. self.read_function = self.polling_read
  719. else:
  720. self.read_function = self.non_polling_read
  721. NetBIOSSession.__init__(self, myname, remote_name, remote_host, remote_type = remote_type, sess_port = sess_port, timeout = timeout, local_type = local_type, sock=sock)
  722. def _setup_connection(self, peer):
  723. try:
  724. af, socktype, proto, canonname, sa = socket.getaddrinfo(peer[0], peer[1], 0, socket.SOCK_STREAM)[0]
  725. sock = socket.socket(af, socktype, proto)
  726. sock.connect(sa)
  727. except socket.error as e:
  728. raise socket.error("Connection error (%s:%s)" % (peer[0], peer[1]), e)
  729. return sock
  730. def send_packet(self, data):
  731. p = NetBIOSSessionPacket()
  732. p.set_type(NETBIOS_SESSION_MESSAGE)
  733. p.set_trailer(data)
  734. self._sock.send(p.rawData())
  735. def recv_packet(self, timeout = None):
  736. data = self.__read(timeout)
  737. return NetBIOSSessionPacket(data)
  738. def _request_session(self, remote_type, local_type, timeout = None):
  739. p = NetBIOSSessionPacket()
  740. remote_name = encode_name(self.get_remote_name(), remote_type, '')
  741. myname = encode_name(self.get_myname(), local_type, '')
  742. p.set_type(NETBIOS_SESSION_REQUEST)
  743. p.set_trailer(remote_name + myname)
  744. self._sock.send(p.rawData())
  745. while 1:
  746. p = self.recv_packet(timeout)
  747. if p.get_type() == NETBIOS_SESSION_NEGATIVE_RESPONSE:
  748. raise NetBIOSError( 'Cannot request session', ERRCLASS_SESSION, ord(p.get_trailer()[0]))
  749. elif p.get_type() == NETBIOS_SESSION_POSITIVE_RESPONSE:
  750. break
  751. else:
  752. # Ignore all other messages, most probably keepalive messages
  753. pass
  754. def polling_read(self, read_length, timeout):
  755. data = ''
  756. if timeout is None:
  757. timeout = 3600
  758. time_left = timeout
  759. CHUNK_TIME = 0.025
  760. bytes_left = read_length
  761. while bytes_left > 0:
  762. try:
  763. ready, _, _ = select.select([self._sock.fileno() ], [ ], [ ], 0)
  764. if not ready:
  765. if time_left <= 0:
  766. raise NetBIOSTimeout
  767. else:
  768. time.sleep(CHUNK_TIME)
  769. time_left -= CHUNK_TIME
  770. continue
  771. received = self._sock.recv(bytes_left)
  772. if len(received) == 0:
  773. raise NetBIOSError( 'Error while reading from remote', ERRCLASS_OS, None)
  774. data = data + received
  775. bytes_left = read_length - len(data)
  776. except select.error as ex:
  777. if ex[0] != errno.EINTR and ex[0] != errno.EAGAIN:
  778. raise NetBIOSError( 'Error occurs while reading from remote', ERRCLASS_OS, ex[0])
  779. return data
  780. def non_polling_read(self, read_length, timeout):
  781. data = ''
  782. bytes_left = read_length
  783. while bytes_left > 0:
  784. try:
  785. ready, _, _ = select.select([self._sock.fileno() ], [ ], [ ], timeout)
  786. if not ready:
  787. raise NetBIOSTimeout
  788. received = self._sock.recv(bytes_left)
  789. if len(received) == 0:
  790. raise NetBIOSError( 'Error while reading from remote', ERRCLASS_OS, None)
  791. data = data + received
  792. bytes_left = read_length - len(data)
  793. except select.error as ex:
  794. if ex[0] != errno.EINTR and ex[0] != errno.EAGAIN:
  795. raise NetBIOSError( 'Error occurs while reading from remote', ERRCLASS_OS, ex[0])
  796. return data
  797. def __read(self, timeout = None):
  798. data = self.read_function(4, timeout)
  799. type, flags, length = unpack('>ccH', data)
  800. if ord(type) == NETBIOS_SESSION_MESSAGE:
  801. length |= ord(flags) << 16
  802. else:
  803. if ord(flags) & 0x01:
  804. length |= 0x10000
  805. data2 = self.read_function(length, timeout)
  806. return data + data2
  807. ERRCLASS_QUERY = 0x00
  808. ERRCLASS_SESSION = 0xf0
  809. ERRCLASS_OS = 0xff
  810. QUERY_ERRORS = { 0x01: 'Request format error. Please file a bug report.',
  811. 0x02: 'Internal server error',
  812. 0x03: 'Name does not exist',
  813. 0x04: 'Unsupported request',
  814. 0x05: 'Request refused'
  815. }
  816. SESSION_ERRORS = { 0x80: 'Not listening on called name',
  817. 0x81: 'Not listening for calling name',
  818. 0x82: 'Called name not present',
  819. 0x83: 'Sufficient resources',
  820. 0x8f: 'Unspecified error'
  821. }
  822. def main():
  823. def get_netbios_host_by_name(name):
  824. n = NetBIOS()
  825. n.set_broadcastaddr('255.255.255.255') # To avoid use "<broadcast>" in socket
  826. for qtype in (TYPE_WORKSTATION, TYPE_CLIENT, TYPE_SERVER, TYPE_DOMAIN_MASTER, TYPE_DOMAIN_CONTROLLER):
  827. try:
  828. addrs = n.gethostbyname(name, qtype = qtype).get_addr_entries()
  829. except NetBIOSTimeout:
  830. continue
  831. else:
  832. return addrs
  833. raise Exception("Host not found")
  834. n = get_netbios_host_by_name("some-host")
  835. print(n)
  836. if __name__ == '__main__':
  837. main()