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