netbios.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. import sys
  2. import win32wnet
  3. import struct
  4. # Constants generated by h2py from nb30.h
  5. NCBNAMSZ = 16
  6. MAX_LANA = 254
  7. NAME_FLAGS_MASK = 0x87
  8. GROUP_NAME = 0x80
  9. UNIQUE_NAME = 0x00
  10. REGISTERING = 0x00
  11. REGISTERED = 0x04
  12. DEREGISTERED = 0x05
  13. DUPLICATE = 0x06
  14. DUPLICATE_DEREG = 0x07
  15. LISTEN_OUTSTANDING = 0x01
  16. CALL_PENDING = 0x02
  17. SESSION_ESTABLISHED = 0x03
  18. HANGUP_PENDING = 0x04
  19. HANGUP_COMPLETE = 0x05
  20. SESSION_ABORTED = 0x06
  21. ALL_TRANSPORTS = "M\0\0\0"
  22. MS_NBF = "MNBF"
  23. NCBCALL = 0x10
  24. NCBLISTEN = 0x11
  25. NCBHANGUP = 0x12
  26. NCBSEND = 0x14
  27. NCBRECV = 0x15
  28. NCBRECVANY = 0x16
  29. NCBCHAINSEND = 0x17
  30. NCBDGSEND = 0x20
  31. NCBDGRECV = 0x21
  32. NCBDGSENDBC = 0x22
  33. NCBDGRECVBC = 0x23
  34. NCBADDNAME = 0x30
  35. NCBDELNAME = 0x31
  36. NCBRESET = 0x32
  37. NCBASTAT = 0x33
  38. NCBSSTAT = 0x34
  39. NCBCANCEL = 0x35
  40. NCBADDGRNAME = 0x36
  41. NCBENUM = 0x37
  42. NCBUNLINK = 0x70
  43. NCBSENDNA = 0x71
  44. NCBCHAINSENDNA = 0x72
  45. NCBLANSTALERT = 0x73
  46. NCBACTION = 0x77
  47. NCBFINDNAME = 0x78
  48. NCBTRACE = 0x79
  49. ASYNCH = 0x80
  50. NRC_GOODRET = 0x00
  51. NRC_BUFLEN = 0x01
  52. NRC_ILLCMD = 0x03
  53. NRC_CMDTMO = 0x05
  54. NRC_INCOMP = 0x06
  55. NRC_BADDR = 0x07
  56. NRC_SNUMOUT = 0x08
  57. NRC_NORES = 0x09
  58. NRC_SCLOSED = 0x0a
  59. NRC_CMDCAN = 0x0b
  60. NRC_DUPNAME = 0x0d
  61. NRC_NAMTFUL = 0x0e
  62. NRC_ACTSES = 0x0f
  63. NRC_LOCTFUL = 0x11
  64. NRC_REMTFUL = 0x12
  65. NRC_ILLNN = 0x13
  66. NRC_NOCALL = 0x14
  67. NRC_NOWILD = 0x15
  68. NRC_INUSE = 0x16
  69. NRC_NAMERR = 0x17
  70. NRC_SABORT = 0x18
  71. NRC_NAMCONF = 0x19
  72. NRC_IFBUSY = 0x21
  73. NRC_TOOMANY = 0x22
  74. NRC_BRIDGE = 0x23
  75. NRC_CANOCCR = 0x24
  76. NRC_CANCEL = 0x26
  77. NRC_DUPENV = 0x30
  78. NRC_ENVNOTDEF = 0x34
  79. NRC_OSRESNOTAV = 0x35
  80. NRC_MAXAPPS = 0x36
  81. NRC_NOSAPS = 0x37
  82. NRC_NORESOURCES = 0x38
  83. NRC_INVADDRESS = 0x39
  84. NRC_INVDDID = 0x3B
  85. NRC_LOCKFAIL = 0x3C
  86. NRC_OPENERR = 0x3f
  87. NRC_SYSTEM = 0x40
  88. NRC_PENDING = 0xff
  89. UCHAR = "B"
  90. WORD = "H"
  91. DWORD = "I"
  92. USHORT = "H"
  93. ULONG = "I"
  94. ADAPTER_STATUS_ITEMS = [
  95. ("6s", "adapter_address"),
  96. (UCHAR, "rev_major"),
  97. (UCHAR, "reserved0"),
  98. (UCHAR, "adapter_type"),
  99. (UCHAR, "rev_minor"),
  100. (WORD, "duration"),
  101. (WORD, "frmr_recv"),
  102. (WORD, "frmr_xmit"),
  103. (WORD, "iframe_recv_err"),
  104. (WORD, "xmit_aborts"),
  105. (DWORD, "xmit_success"),
  106. (DWORD, "recv_success"),
  107. (WORD, "iframe_xmit_err"),
  108. (WORD, "recv_buff_unavail"),
  109. (WORD, "t1_timeouts"),
  110. (WORD, "ti_timeouts"),
  111. (DWORD, "reserved1"),
  112. (WORD, "free_ncbs"),
  113. (WORD, "max_cfg_ncbs"),
  114. (WORD, "max_ncbs"),
  115. (WORD, "xmit_buf_unavail"),
  116. (WORD, "max_dgram_size"),
  117. (WORD, "pending_sess"),
  118. (WORD, "max_cfg_sess"),
  119. (WORD, "max_sess"),
  120. (WORD, "max_sess_pkt_size"),
  121. (WORD, "name_count"),
  122. ]
  123. NAME_BUFFER_ITEMS = [
  124. (str(NCBNAMSZ) + "s", "name"),
  125. (UCHAR, "name_num"),
  126. (UCHAR, "name_flags"),
  127. ]
  128. SESSION_HEADER_ITEMS = [
  129. (UCHAR, "sess_name"),
  130. (UCHAR, "num_sess"),
  131. (UCHAR, "rcv_dg_outstanding"),
  132. (UCHAR, "rcv_any_outstanding"),
  133. ]
  134. SESSION_BUFFER_ITEMS = [
  135. (UCHAR, "lsn"),
  136. (UCHAR, "state"),
  137. (str(NCBNAMSZ)+"s", "local_name"),
  138. (str(NCBNAMSZ)+"s", "remote_name"),
  139. (UCHAR, "rcvs_outstanding"),
  140. (UCHAR, "sends_outstanding"),
  141. ]
  142. LANA_ENUM_ITEMS = [
  143. ("B", "length"), # Number of valid entries in lana[]
  144. (str(MAX_LANA+1) + "s", "lana"),
  145. ]
  146. FIND_NAME_HEADER_ITEMS = [
  147. (WORD, "node_count"),
  148. (UCHAR, "reserved"),
  149. (UCHAR, "unique_group"),
  150. ]
  151. FIND_NAME_BUFFER_ITEMS = [
  152. (UCHAR, "length"),
  153. (UCHAR, "access_control"),
  154. (UCHAR, "frame_control"),
  155. ("6s", "destination_addr"),
  156. ("6s", "source_addr"),
  157. ("18s", "routing_info"),
  158. ]
  159. ACTION_HEADER_ITEMS = [
  160. (ULONG, "transport_id"),
  161. (USHORT, "action_code"),
  162. (USHORT, "reserved"),
  163. ]
  164. del UCHAR, WORD, DWORD, USHORT, ULONG
  165. NCB = win32wnet.NCB
  166. def Netbios(ncb):
  167. ob = ncb.Buffer
  168. is_ours = hasattr(ob, "_pack")
  169. if is_ours:
  170. ob._pack()
  171. try:
  172. return win32wnet.Netbios(ncb)
  173. finally:
  174. if is_ours:
  175. ob._unpack()
  176. class NCBStruct:
  177. def __init__(self, items):
  178. self._format = "".join([item[0] for item in items])
  179. self._items = items
  180. self._buffer_ = win32wnet.NCBBuffer(struct.calcsize(self._format))
  181. for format, name in self._items:
  182. if len(format)==1:
  183. if format == 'c':
  184. val = '\0'
  185. else:
  186. val = 0
  187. else:
  188. l = int(format[:-1])
  189. val = '\0' * l
  190. self.__dict__[name] = val
  191. def _pack(self):
  192. vals = []
  193. for format, name in self._items:
  194. try:
  195. vals.append(self.__dict__[name])
  196. except KeyError:
  197. vals.append(None)
  198. self._buffer_[:] = struct.pack(*(self._format,) + tuple(vals))
  199. def _unpack(self):
  200. items = struct.unpack(self._format, self._buffer_)
  201. assert len(items)==len(self._items), "unexpected number of items to unpack!"
  202. for (format, name), val in zip(self._items, items):
  203. self.__dict__[name] = val
  204. def __setattr__(self, attr, val):
  205. if attr not in self.__dict__ and attr[0]!='_':
  206. for format, attr_name in self._items:
  207. if attr==attr_name:
  208. break
  209. else:
  210. raise AttributeError(attr)
  211. self.__dict__[attr] = val
  212. def ADAPTER_STATUS():
  213. return NCBStruct(ADAPTER_STATUS_ITEMS)
  214. def NAME_BUFFER():
  215. return NCBStruct(NAME_BUFFER_ITEMS)
  216. def SESSION_HEADER():
  217. return NCBStruct(SESSION_HEADER_ITEMS)
  218. def SESSION_BUFFER():
  219. return NCBStruct(SESSION_BUFFER_ITEMS)
  220. def LANA_ENUM():
  221. return NCBStruct(LANA_ENUM_ITEMS)
  222. def FIND_NAME_HEADER():
  223. return NCBStruct(FIND_NAME_HEADER_ITEMS)
  224. def FIND_NAME_BUFFER():
  225. return NCBStruct(FIND_NAME_BUFFER_ITEMS)
  226. def ACTION_HEADER():
  227. return NCBStruct(ACTION_HEADER_ITEMS)
  228. def byte_to_int(b):
  229. """Given an element in a binary buffer, return its integer value"""
  230. if sys.version_info >= (3,0):
  231. # a byte is already an int in py3k
  232. return b
  233. return ord(b) # its a char from a string in py2k.
  234. if __name__=='__main__':
  235. # code ported from "HOWTO: Get the MAC Address for an Ethernet Adapter"
  236. # MS KB ID: Q118623
  237. ncb = NCB()
  238. ncb.Command = NCBENUM
  239. la_enum = LANA_ENUM()
  240. ncb.Buffer = la_enum
  241. rc = Netbios(ncb)
  242. if rc != 0: raise RuntimeError("Unexpected result %d" % (rc,))
  243. for i in range(la_enum.length):
  244. ncb.Reset()
  245. ncb.Command = NCBRESET
  246. ncb.Lana_num = byte_to_int(la_enum.lana[i])
  247. rc = Netbios(ncb)
  248. if rc != 0: raise RuntimeError("Unexpected result %d" % (rc,))
  249. ncb.Reset()
  250. ncb.Command = NCBASTAT
  251. ncb.Lana_num = byte_to_int(la_enum.lana[i])
  252. ncb.Callname = "* ".encode("ascii") # ensure bytes on py2x and 3k
  253. adapter = ADAPTER_STATUS()
  254. ncb.Buffer = adapter
  255. Netbios(ncb)
  256. print("Adapter address:", end=' ')
  257. for ch in adapter.adapter_address:
  258. print("%02x" % (byte_to_int(ch),), end=' ')
  259. print()