/src/wireshark/epan/dissectors/packet-nbipx.c
Line | Count | Source |
1 | | /* packet-nbipx.c |
2 | | * Routines for NetBIOS over IPX packet disassembly |
3 | | * Gilbert Ramirez <gram@alumni.rice.edu> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | #include "config.h" |
13 | | |
14 | | #include <epan/packet.h> |
15 | | #include <epan/tfs.h> |
16 | | #include <wsutil/array.h> |
17 | | #include "packet-ipx.h" |
18 | | #include "packet-netbios.h" |
19 | | |
20 | | void proto_register_nbipx(void); |
21 | | void proto_reg_handoff_nbipx(void); |
22 | | void proto_register_nmpi(void); |
23 | | void proto_reg_handoff_nmpi(void); |
24 | | |
25 | | static dissector_handle_t nbipx_handle; |
26 | | static dissector_handle_t nmpi_handle; |
27 | | |
28 | | static int proto_nbipx; |
29 | | static int hf_nbipx_packettype; |
30 | | static int hf_nbipx_name_flags; |
31 | | static int hf_nbipx_name_flags_group; |
32 | | static int hf_nbipx_name_flags_in_use; |
33 | | static int hf_nbipx_name_flags_registered; |
34 | | static int hf_nbipx_name_flags_duplicated; |
35 | | static int hf_nbipx_name_flags_deregistered; |
36 | | static int hf_nbipx_conn_control; |
37 | | static int hf_nbipx_conn_control_sys_packet; |
38 | | static int hf_nbipx_conn_control_ack; |
39 | | static int hf_nbipx_conn_control_attention; |
40 | | static int hf_nbipx_conn_control_end_msg; |
41 | | static int hf_nbipx_conn_control_resend; |
42 | | static int hf_nbipx_session_src_conn_id; |
43 | | static int hf_nbipx_session_dest_conn_id; |
44 | | static int hf_nbipx_session_send_seq_number; |
45 | | static int hf_nbipx_session_total_data_length; |
46 | | static int hf_nbipx_session_offset; |
47 | | static int hf_nbipx_session_data_length; |
48 | | static int hf_nbipx_session_recv_seq_number; |
49 | | static int hf_nbipx_session_bytes_received; |
50 | | static int hf_nbipx_ipx_network; |
51 | | static int hf_nbipx_opcode; |
52 | | static int hf_nbipx_name_type; |
53 | | static int hf_nbipx_messageid; |
54 | | |
55 | | static int ett_nbipx; |
56 | | static int ett_nbipx_conn_ctrl; |
57 | | static int ett_nbipx_name_type_flags; |
58 | | |
59 | | static void dissect_conn_control(tvbuff_t *tvb, unsigned offset, proto_tree *tree); |
60 | | |
61 | | static heur_dissector_list_t netbios_heur_subdissector_list; |
62 | | |
63 | | /* There is no RFC or public specification of Netware or Microsoft |
64 | | * NetBIOS over IPX packets. I have had to decode the protocol myself, |
65 | | * so there are holes and perhaps errors in this code. (gram) |
66 | | * |
67 | | * A list of "NovelNetBIOS" packet types can be found at |
68 | | * |
69 | | * http://web.archive.org/web/20150319134837/http://www.protocols.com/pbook/novel.htm#NetBIOS |
70 | | * |
71 | | * and at least some of those packet types appear to match what's in |
72 | | * some NBIPX packets. |
73 | | * |
74 | | * Note, however, that it appears that sometimes NBIPX packets have |
75 | | * 8 IPX addresses at the beginning, and sometimes they don't. |
76 | | * |
77 | | * In the section on "NetBIOS Broadcasts", the document at |
78 | | * |
79 | | * http://www.microsoft.com/technet/network/ipxrout.asp |
80 | | * |
81 | | * says that "the NetBIOS over IPX Broadcast header" contains 8 IPX |
82 | | * network numbers in the "IPX WAN broadcast header", and that it's |
83 | | * followed by a "Name Type Flags" byte (giving information about the |
84 | | * name being registered, deregistered, or checked), a "Data Stream |
85 | | * Type 2" byte giving the type of operation (NBIPX_FIND_NAME, |
86 | | * NBIPX_NAME_RECOGNIZED, or NBIPX_CHECK_NAME - the latter is called |
87 | | * "Add Name"), and a 16-byte NetBIOS name. |
88 | | * |
89 | | * It also says that "NetBIOS over IPX Broadcast packets" have a |
90 | | * packet type of 0x14 (20, or IPX_PACKET_TYPE_WANBCAST) and a |
91 | | * socket number of 0x455 (IPX_SOCKET_NETBIOS). |
92 | | * |
93 | | * However, there are also non-broadcast packets that *also* contain |
94 | | * the 8 IPX network numbers; they appear to be replies to broadcast |
95 | | * packets, and have a packet type of 0x4 (IPX_PACKET_TYPE_PEP). |
96 | | * |
97 | | * Other IPX_PACKET_TYPE_PEP packets to and from the IPX_SOCKET_NETBIOS |
98 | | * socket, however, *don't* have the 8 IPX network numbers; there does |
99 | | * not seem to be any obvious algorithm to determine whether the packet |
100 | | * has the addresses or not. Microsoft Knowledge Base article Q128335 |
101 | | * appears to show some code from the NBIPX implementation in NT that |
102 | | * tries to determine the packet type - and it appears to use heuristics |
103 | | * based on the packet length and on looking at what might be the NBIPX |
104 | | * "Data Stream Type" byte depending on whether the packet has the 8 |
105 | | * IPX network numbers or not. |
106 | | * |
107 | | * So, for now, we treat *all* NBIPX packets as having a "Data Stream |
108 | | * Type" byte, preceded by another byte of NBIPX information and |
109 | | * followed by more NBIPX stuff, and assume that it's preceded by |
110 | | * 8 IPX network numbers iff: |
111 | | * |
112 | | * the packet is a WAN Broadcast packet |
113 | | * |
114 | | * or |
115 | | * |
116 | | * the packet is the right size for one of those PEP name replies |
117 | | * (50 bytes) *and* has a name packet type as the Data Stream |
118 | | * Type byte at the offset where that byte would be if the packet |
119 | | * does have the 8 IPX network numbers at the beginning. |
120 | | * |
121 | | * The page at |
122 | | * |
123 | | * http://ourworld.compuserve.com/homepages/TimothyDEvans/encap.htm |
124 | | * |
125 | | * indicates, under "NBIPX session packets", that "NBIPX session packets" |
126 | | * have |
127 | | * |
128 | | * 1 byte of NBIPX connection control flag |
129 | | * 1 byte of data stream type |
130 | | * 2 bytes of source connection ID |
131 | | * 2 bytes of destination connection ID |
132 | | * 2 bytes of send sequence number |
133 | | * 2 bytes of total data length |
134 | | * 2 bytes of offset |
135 | | * 2 bytes of data length |
136 | | * 2 bytes of receive sequence number |
137 | | * 2 bytes of "bytes received" |
138 | | * |
139 | | * followed by data. |
140 | | * |
141 | | * Packets with a data stream type of NBIPX_DIRECTED_DATAGRAM appear to |
142 | | * have, following the data stream type, two NetBIOS names, the first |
143 | | * of which is the receiver's NetBIOS name and the second of which is |
144 | | * the sender's NetBIOS name. The page at |
145 | | * |
146 | | * http://support.microsoft.com/support/kb/articles/q203/0/51.asp |
147 | | * |
148 | | * speaks of type 4 (PEP) packets as being used for "SAP, NetBIOS sessions |
149 | | * and directed datagrams" and type 20 (WAN Broadcast) as being used for |
150 | | * "NetBIOS name resolution broadcasts" (but nothing about the non-broadcast |
151 | | * type 4 name resolution stuff). |
152 | | * |
153 | | * We assume that this means that, once you get past the 8 IPX network |
154 | | * numbers if present: |
155 | | * |
156 | | * the first byte is a name type byte for the name packets |
157 | | * and a connection control flag for the other packets; |
158 | | * |
159 | | * the second byte is a data stream type; |
160 | | * |
161 | | * the rest of the bytes are: |
162 | | * |
163 | | * the NetBIOS name being registered/deregistered/etc., |
164 | | * for name packets; |
165 | | * |
166 | | * the two NetBIOS names, followed by the NetBIOS |
167 | | * datagram, for NBIPX_DIRECTED_DATAGRAM packets; |
168 | | * |
169 | | * the session packet header, possibly followed by |
170 | | * session data, for session packets. |
171 | | * |
172 | | * We don't know yet how to interpret NBIPX_STATUS_QUERY or |
173 | | * NBIPX_STATUS_RESPONSE. |
174 | | * |
175 | | * For now, we treat the datagrams and session data as SMB stuff. |
176 | | */ |
177 | 0 | #define NBIPX_FIND_NAME 1 |
178 | 0 | #define NBIPX_NAME_RECOGNIZED 2 |
179 | 0 | #define NBIPX_CHECK_NAME 3 |
180 | 0 | #define NBIPX_NAME_IN_USE 4 |
181 | 5 | #define NBIPX_DEREGISTER_NAME 5 |
182 | 0 | #define NBIPX_SESSION_DATA 6 |
183 | 0 | #define NBIPX_SESSION_END 7 |
184 | 0 | #define NBIPX_SESSION_END_ACK 8 |
185 | | #define NBIPX_STATUS_QUERY 9 |
186 | | #define NBIPX_STATUS_RESPONSE 10 |
187 | 0 | #define NBIPX_DIRECTED_DATAGRAM 11 |
188 | | |
189 | | static const value_string nbipx_data_stream_type_vals[] = { |
190 | | {NBIPX_FIND_NAME, "Find name"}, |
191 | | {NBIPX_NAME_RECOGNIZED, "Name recognized"}, |
192 | | {NBIPX_CHECK_NAME, "Check name"}, |
193 | | {NBIPX_NAME_IN_USE, "Name in use"}, |
194 | | {NBIPX_DEREGISTER_NAME, "Deregister name"}, |
195 | | {NBIPX_SESSION_DATA, "Session data"}, |
196 | | {NBIPX_SESSION_END, "Session end"}, |
197 | | {NBIPX_SESSION_END_ACK, "Session end ACK"}, |
198 | | {NBIPX_STATUS_QUERY, "Status query"}, |
199 | | {NBIPX_STATUS_RESPONSE, "Status response"}, |
200 | | {NBIPX_DIRECTED_DATAGRAM, "Directed datagram"}, |
201 | | {0, NULL} |
202 | | }; |
203 | | |
204 | | /* |
205 | | * Opcodes. |
206 | | */ |
207 | 0 | #define INAME_CLAIM 0xf1 |
208 | 1 | #define INAME_DELETE 0xf2 |
209 | 1 | #define INAME_QUERY 0xf3 |
210 | 1 | #define INAME_FOUND 0xf4 |
211 | 2 | #define IMSG_HANGUP 0xf5 |
212 | 105 | #define IMSLOT_SEND 0xfc |
213 | 1 | #define IMSLOT_FIND 0xfd |
214 | 6 | #define IMSLOT_NAME 0xfe |
215 | | |
216 | | static const value_string nmpi_opcode_vals[] = { |
217 | | {INAME_CLAIM, "Claim name"}, |
218 | | {INAME_DELETE, "Delete name"}, |
219 | | {INAME_QUERY, "Query name"}, |
220 | | {INAME_FOUND, "Name found"}, |
221 | | {IMSG_HANGUP, "Messenger hangup"}, |
222 | | {IMSLOT_SEND, "Mailslot write"}, |
223 | | {IMSLOT_FIND, "Find mailslot name"}, |
224 | | {IMSLOT_NAME, "Mailslot name found"}, |
225 | | {0, NULL} |
226 | | }; |
227 | | |
228 | | /* |
229 | | * Name types. |
230 | | */ |
231 | | #define INTYPE_MACHINE 1 |
232 | | #define INTYPE_WORKGROUP 2 |
233 | | #define INTYPE_BROWSER 3 |
234 | | |
235 | | static const value_string nmpi_name_type_vals[] = { |
236 | | {INTYPE_MACHINE, "Machine"}, |
237 | | {INTYPE_WORKGROUP, "Workgroup"}, |
238 | | {INTYPE_BROWSER, "Browser"}, |
239 | | {0, NULL} |
240 | | }; |
241 | | |
242 | | static const true_false_string tfs_system_non_system = { "System packet", "Non-system packet" }; |
243 | | |
244 | | static void |
245 | | add_routers(proto_tree *tree, tvbuff_t *tvb, unsigned offset) |
246 | 108 | { |
247 | 108 | int i; |
248 | | |
249 | | /* Eight routers are listed */ |
250 | 941 | for (i = 0; i < 8; i++) { |
251 | 833 | if (tvb_get_ntohl(tvb, offset) != 0) { |
252 | 705 | proto_tree_add_item(tree, hf_nbipx_ipx_network, tvb, offset, 4, ENC_NA); |
253 | 705 | } |
254 | 833 | offset += 4; |
255 | 833 | } |
256 | 108 | } |
257 | | |
258 | | static void |
259 | | dissect_netbios_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) |
260 | 3 | { |
261 | 3 | heur_dtbl_entry_t *hdtbl_entry; |
262 | | |
263 | | /* |
264 | | * Try the heuristic dissectors for NetBIOS; if none of them |
265 | | * accept the packet, dissect it as data. |
266 | | */ |
267 | 3 | if (!dissector_try_heuristic(netbios_heur_subdissector_list, |
268 | 3 | tvb, pinfo, tree, &hdtbl_entry, NULL)) |
269 | 3 | call_data_dissector(tvb, pinfo, tree); |
270 | 3 | } |
271 | | |
272 | | static int |
273 | | dissect_nbipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) |
274 | 9 | { |
275 | 9 | bool has_routes; |
276 | 9 | proto_tree *nbipx_tree = NULL; |
277 | 9 | proto_item *ti = NULL; |
278 | 9 | unsigned offset = 0; |
279 | 9 | uint8_t packet_type; |
280 | 9 | proto_tree *name_type_flag_tree; |
281 | 9 | proto_item *tf; |
282 | 9 | char name[(NETBIOS_NAME_LEN - 1)*4 + 1]; |
283 | 9 | int name_type; |
284 | 9 | bool has_payload; |
285 | 9 | tvbuff_t *next_tvb; |
286 | 9 | ipxhdr_t *ipxh; |
287 | | |
288 | | /* Reject the packet if data is NULL */ |
289 | 9 | if (data == NULL) |
290 | 0 | return 0; |
291 | 9 | ipxh = (ipxhdr_t*)data; |
292 | | |
293 | 9 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBIPX"); |
294 | 9 | col_clear(pinfo->cinfo, COL_INFO); |
295 | | |
296 | 9 | if (ipxh->ipx_type == IPX_PACKET_TYPE_WANBCAST) { |
297 | | /* |
298 | | * This is a WAN Broadcast packet; we assume it will have |
299 | | * 8 IPX addresses at the beginning. |
300 | | */ |
301 | 0 | has_routes = true; |
302 | 9 | } else { |
303 | | /* |
304 | | * This isn't a WAN Broadcast packet, but it still might |
305 | | * have the 8 addresses. |
306 | | * |
307 | | * If it's the right length for a name operation, |
308 | | * and, if we assume it has routes, the packet type |
309 | | * is a name operation, assume it has routes. |
310 | | * |
311 | | * NOTE: this will throw an exception if the byte that |
312 | | * would be the packet type byte if this has the 8 |
313 | | * addresses isn't present; if that's the case, we don't |
314 | | * know how to interpret this packet, so we can't dissect |
315 | | * it anyway. |
316 | | */ |
317 | 9 | has_routes = false; /* start out assuming it doesn't */ |
318 | 9 | if (tvb_reported_length(tvb) == 50) { |
319 | 3 | packet_type = tvb_get_uint8(tvb, offset + 32 + 1); |
320 | 3 | switch (packet_type) { |
321 | | |
322 | 0 | case NBIPX_FIND_NAME: |
323 | 0 | case NBIPX_NAME_RECOGNIZED: |
324 | 0 | case NBIPX_CHECK_NAME: |
325 | 0 | case NBIPX_NAME_IN_USE: |
326 | 0 | case NBIPX_DEREGISTER_NAME: |
327 | 0 | has_routes = true; |
328 | 0 | break; |
329 | 3 | } |
330 | 3 | } |
331 | 9 | } |
332 | | |
333 | 9 | if (tree) { |
334 | 9 | ti = proto_tree_add_item(tree, proto_nbipx, tvb, 0, |
335 | 9 | -1, ENC_NA); |
336 | 9 | nbipx_tree = proto_item_add_subtree(ti, ett_nbipx); |
337 | 9 | } |
338 | | |
339 | 9 | if (has_routes) { |
340 | 0 | if (tree) |
341 | 0 | add_routers(nbipx_tree, tvb, 0); |
342 | 0 | offset += 32; |
343 | 0 | } |
344 | | |
345 | 9 | packet_type = tvb_get_uint8(tvb, offset + 1); |
346 | | |
347 | 9 | switch (packet_type) { |
348 | | |
349 | 0 | case NBIPX_FIND_NAME: |
350 | 0 | case NBIPX_NAME_RECOGNIZED: |
351 | 0 | case NBIPX_CHECK_NAME: |
352 | 0 | case NBIPX_NAME_IN_USE: |
353 | 5 | case NBIPX_DEREGISTER_NAME: |
354 | 5 | name_type = get_netbios_name(tvb, offset+2, name, (NETBIOS_NAME_LEN - 1)*4 + 1); |
355 | 5 | col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s<%02x>", |
356 | 5 | val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown"), |
357 | 5 | name, name_type); |
358 | | |
359 | 5 | if (nbipx_tree) { |
360 | 5 | tf = proto_tree_add_item(nbipx_tree, hf_nbipx_name_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
361 | 5 | name_type_flag_tree = proto_item_add_subtree(tf, ett_nbipx_name_type_flags); |
362 | | |
363 | 5 | proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_group, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
364 | 5 | proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_in_use, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
365 | 5 | proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_registered, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
366 | 5 | proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_duplicated, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
367 | 5 | proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_deregistered, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
368 | 5 | } |
369 | 5 | offset += 1; |
370 | | |
371 | 5 | proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); |
372 | 5 | offset += 1; |
373 | | |
374 | 5 | if (nbipx_tree) |
375 | 5 | netbios_add_name("Name", tvb, offset, nbipx_tree); |
376 | 5 | offset += NETBIOS_NAME_LEN; |
377 | | |
378 | | /* |
379 | | * No payload to be interpreted by another protocol. |
380 | | */ |
381 | 5 | has_payload = false; |
382 | 5 | break; |
383 | | |
384 | 0 | case NBIPX_SESSION_DATA: |
385 | 0 | case NBIPX_SESSION_END: |
386 | 0 | case NBIPX_SESSION_END_ACK: |
387 | 0 | col_set_str(pinfo->cinfo, COL_INFO, |
388 | 0 | val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown")); |
389 | |
|
390 | 0 | dissect_conn_control(tvb, offset, nbipx_tree); |
391 | 0 | offset += 1; |
392 | |
|
393 | 0 | proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); |
394 | 0 | offset += 1; |
395 | |
|
396 | 0 | proto_tree_add_item(nbipx_tree, hf_nbipx_session_src_conn_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
397 | 0 | offset += 2; |
398 | |
|
399 | 0 | proto_tree_add_item(nbipx_tree, hf_nbipx_session_dest_conn_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
400 | 0 | offset += 2; |
401 | |
|
402 | 0 | proto_tree_add_item(nbipx_tree, hf_nbipx_session_send_seq_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
403 | 0 | offset += 2; |
404 | |
|
405 | 0 | proto_tree_add_item(nbipx_tree, hf_nbipx_session_total_data_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
406 | 0 | offset += 2; |
407 | |
|
408 | 0 | proto_tree_add_item(nbipx_tree, hf_nbipx_session_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
409 | 0 | offset += 2; |
410 | |
|
411 | 0 | proto_tree_add_item(nbipx_tree, hf_nbipx_session_data_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
412 | 0 | offset += 2; |
413 | |
|
414 | 0 | proto_tree_add_item(nbipx_tree, hf_nbipx_session_recv_seq_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
415 | 0 | offset += 2; |
416 | |
|
417 | 0 | proto_tree_add_item(nbipx_tree, hf_nbipx_session_bytes_received, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
418 | 0 | offset += 2; |
419 | | |
420 | | /* |
421 | | * We may have payload to dissect. |
422 | | */ |
423 | 0 | has_payload = true; |
424 | 0 | break; |
425 | | |
426 | 0 | case NBIPX_DIRECTED_DATAGRAM: |
427 | 0 | col_set_str(pinfo->cinfo, COL_INFO, |
428 | 0 | val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown")); |
429 | |
|
430 | 0 | dissect_conn_control(tvb, offset, nbipx_tree); |
431 | 0 | offset += 1; |
432 | |
|
433 | 0 | proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); |
434 | 0 | offset += 1; |
435 | |
|
436 | 0 | if (nbipx_tree) |
437 | 0 | netbios_add_name("Receiver's Name", tvb, offset, |
438 | 0 | nbipx_tree); |
439 | 0 | offset += NETBIOS_NAME_LEN; |
440 | |
|
441 | 0 | if (nbipx_tree) |
442 | 0 | netbios_add_name("Sender's Name", tvb, offset, |
443 | 0 | nbipx_tree); |
444 | 0 | offset += NETBIOS_NAME_LEN; |
445 | | |
446 | | /* |
447 | | * We may have payload to dissect. |
448 | | */ |
449 | 0 | has_payload = true; |
450 | 0 | break; |
451 | | |
452 | 4 | default: |
453 | 4 | col_set_str(pinfo->cinfo, COL_INFO, |
454 | 4 | val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown")); |
455 | | |
456 | | /* |
457 | | * We don't know what the first byte is. |
458 | | */ |
459 | 4 | offset += 1; |
460 | | |
461 | | /* |
462 | | * The second byte is a data stream type byte. |
463 | | */ |
464 | 4 | proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); |
465 | 4 | offset += 1; |
466 | | |
467 | | /* |
468 | | * We don't know what the rest of the packet is. |
469 | | */ |
470 | 4 | has_payload = false; |
471 | 9 | } |
472 | | |
473 | | /* |
474 | | * Set the length of the NBIPX tree item. |
475 | | */ |
476 | 9 | if (ti != NULL) |
477 | 9 | proto_item_set_len(ti, offset); |
478 | | |
479 | 9 | if (has_payload && tvb_offset_exists(tvb, offset)) { |
480 | 0 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
481 | 0 | dissect_netbios_payload(next_tvb, pinfo, tree); |
482 | 0 | } |
483 | | |
484 | 9 | return tvb_captured_length(tvb); |
485 | 9 | } |
486 | | |
487 | | static void |
488 | | dissect_conn_control(tvbuff_t *tvb, unsigned offset, proto_tree *tree) |
489 | 0 | { |
490 | 0 | proto_item *ti; |
491 | 0 | proto_tree *cc_tree; |
492 | |
|
493 | 0 | if (tree) { |
494 | 0 | ti = proto_tree_add_item(tree, hf_nbipx_conn_control, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
495 | 0 | cc_tree = proto_item_add_subtree(ti, ett_nbipx_conn_ctrl); |
496 | 0 | proto_tree_add_item(cc_tree, hf_nbipx_conn_control_sys_packet, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
497 | 0 | proto_tree_add_item(cc_tree, hf_nbipx_conn_control_ack, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
498 | 0 | proto_tree_add_item(cc_tree, hf_nbipx_conn_control_attention, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
499 | 0 | proto_tree_add_item(cc_tree, hf_nbipx_conn_control_end_msg, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
500 | 0 | proto_tree_add_item(cc_tree, hf_nbipx_conn_control_resend, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
501 | 0 | } |
502 | 0 | } |
503 | | |
504 | | void |
505 | | proto_register_nbipx(void) |
506 | 15 | { |
507 | 15 | static hf_register_info hf[] = { |
508 | 15 | { &hf_nbipx_packettype, |
509 | 15 | { "Packet Type", "nmpi.packettype", |
510 | 15 | FT_UINT8, BASE_HEX, VALS(nbipx_data_stream_type_vals), 0, |
511 | 15 | NULL, HFILL } |
512 | 15 | }, |
513 | 15 | { &hf_nbipx_name_flags, |
514 | 15 | { "Name type flag", "nmpi.name_flags", |
515 | 15 | FT_UINT8, BASE_HEX, NULL, 0, |
516 | 15 | NULL, HFILL } |
517 | 15 | }, |
518 | 15 | { &hf_nbipx_name_flags_group, |
519 | 15 | { "Name", "nmpi.name_flags.group", |
520 | 15 | FT_BOOLEAN, 8, TFS(&tfs_group_unique_name), 0x80, |
521 | 15 | NULL, HFILL } |
522 | 15 | }, |
523 | 15 | { &hf_nbipx_name_flags_in_use, |
524 | 15 | { "In use", "nmpi.name_flags.in_use", |
525 | 15 | FT_BOOLEAN, 8, TFS(&tfs_used_notused), 0x40, |
526 | 15 | NULL, HFILL } |
527 | 15 | }, |
528 | 15 | { &hf_nbipx_name_flags_registered, |
529 | 15 | { "Registered", "nmpi.name_flags.registered", |
530 | 15 | FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04, |
531 | 15 | NULL, HFILL } |
532 | 15 | }, |
533 | 15 | { &hf_nbipx_name_flags_duplicated, |
534 | 15 | { "Duplicated", "nmpi.name_flags.duplicated", |
535 | 15 | FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02, |
536 | 15 | NULL, HFILL } |
537 | 15 | }, |
538 | 15 | { &hf_nbipx_name_flags_deregistered, |
539 | 15 | { "Deregistered", "nmpi.name_flags.deregistered", |
540 | 15 | FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, |
541 | 15 | NULL, HFILL } |
542 | 15 | }, |
543 | 15 | { &hf_nbipx_conn_control, |
544 | 15 | { "Connection control", "nmpi.conn_control", |
545 | 15 | FT_UINT8, BASE_HEX, NULL, 0, |
546 | 15 | NULL, HFILL } |
547 | 15 | }, |
548 | 15 | { &hf_nbipx_conn_control_sys_packet, |
549 | 15 | { "Packet", "nmpi.conn_control.sys_packet", |
550 | 15 | FT_BOOLEAN, 8, TFS(&tfs_system_non_system), 0x80, |
551 | 15 | NULL, HFILL } |
552 | 15 | }, |
553 | 15 | { &hf_nbipx_conn_control_ack, |
554 | 15 | { "Acknowledgement", "nmpi.conn_control.ack", |
555 | 15 | FT_BOOLEAN, 8, TFS(&tfs_required_not_required), 0x40, |
556 | 15 | NULL, HFILL } |
557 | 15 | }, |
558 | 15 | { &hf_nbipx_conn_control_attention, |
559 | 15 | { "Attention", "nmpi.conn_control.attention", |
560 | 15 | FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20, |
561 | 15 | NULL, HFILL } |
562 | 15 | }, |
563 | 15 | { &hf_nbipx_conn_control_end_msg, |
564 | 15 | { "End of message", "nmpi.conn_control.end_msg", |
565 | 15 | FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x10, |
566 | 15 | NULL, HFILL } |
567 | 15 | }, |
568 | 15 | { &hf_nbipx_conn_control_resend, |
569 | 15 | { "Resend", "nmpi.conn_control.resend", |
570 | 15 | FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08, |
571 | 15 | NULL, HFILL } |
572 | 15 | }, |
573 | 15 | { &hf_nbipx_session_src_conn_id, |
574 | 15 | { "Source connection ID", "nmpi.session.src_conn_id", |
575 | 15 | FT_UINT16, BASE_HEX, NULL, 0, |
576 | 15 | NULL, HFILL } |
577 | 15 | }, |
578 | 15 | { &hf_nbipx_session_dest_conn_id, |
579 | 15 | { "Destination connection ID", "nmpi.session.dest_conn_id", |
580 | 15 | FT_UINT16, BASE_HEX, NULL, 0, |
581 | 15 | NULL, HFILL } |
582 | 15 | }, |
583 | 15 | { &hf_nbipx_session_send_seq_number, |
584 | 15 | { "Send sequence number", "nmpi.session.send_seq_number", |
585 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
586 | 15 | NULL, HFILL } |
587 | 15 | }, |
588 | 15 | { &hf_nbipx_session_total_data_length, |
589 | 15 | { "Total data length", "nmpi.session.total_data_length", |
590 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
591 | 15 | NULL, HFILL } |
592 | 15 | }, |
593 | 15 | { &hf_nbipx_session_offset, |
594 | 15 | { "Offset", "nmpi.session.offset", |
595 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
596 | 15 | NULL, HFILL } |
597 | 15 | }, |
598 | 15 | { &hf_nbipx_session_data_length, |
599 | 15 | { "Data length", "nmpi.session.data_length", |
600 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
601 | 15 | NULL, HFILL } |
602 | 15 | }, |
603 | 15 | { &hf_nbipx_session_recv_seq_number, |
604 | 15 | { "Receive sequence number", "nmpi.session.recv_seq_number", |
605 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
606 | 15 | NULL, HFILL } |
607 | 15 | }, |
608 | 15 | { &hf_nbipx_session_bytes_received, |
609 | 15 | { "Bytes received", "nmpi.session.bytes_received", |
610 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
611 | 15 | NULL, HFILL } |
612 | 15 | }, |
613 | 15 | { &hf_nbipx_ipx_network, |
614 | 15 | { "IPX Network", "nmpi.ipx_network", |
615 | 15 | FT_IPXNET, BASE_NONE, NULL, 0, |
616 | 15 | NULL, HFILL } |
617 | 15 | }, |
618 | 15 | { &hf_nbipx_opcode, |
619 | 15 | { "Opcode", "nmpi.opcode", |
620 | 15 | FT_UINT8, BASE_HEX, VALS(nmpi_opcode_vals), 0, |
621 | 15 | NULL, HFILL } |
622 | 15 | }, |
623 | 15 | { &hf_nbipx_name_type, |
624 | 15 | { "Name Type", "nmpi.name_type", |
625 | 15 | FT_UINT8, BASE_HEX, VALS(nmpi_name_type_vals), 0, |
626 | 15 | NULL, HFILL } |
627 | 15 | }, |
628 | 15 | { &hf_nbipx_messageid, |
629 | 15 | { "Message ID", "nmpi.messageid", |
630 | 15 | FT_UINT16, BASE_HEX, NULL, 0, |
631 | 15 | NULL, HFILL } |
632 | 15 | }, |
633 | 15 | }; |
634 | | |
635 | 15 | static int *ett[] = { |
636 | 15 | &ett_nbipx, |
637 | 15 | &ett_nbipx_conn_ctrl, |
638 | 15 | &ett_nbipx_name_type_flags, |
639 | 15 | }; |
640 | | |
641 | 15 | proto_nbipx = proto_register_protocol("NetBIOS over IPX", "NBIPX", "nbipx"); |
642 | 15 | proto_register_field_array(proto_nbipx, hf, array_length(hf)); |
643 | 15 | proto_register_subtree_array(ett, array_length(ett)); |
644 | | |
645 | 15 | nbipx_handle = register_dissector("nbipx", dissect_nbipx, proto_nbipx); |
646 | 15 | } |
647 | | |
648 | | void |
649 | | proto_reg_handoff_nbipx(void) |
650 | 15 | { |
651 | 15 | dissector_add_uint("ipx.socket", IPX_SOCKET_NETBIOS, nbipx_handle); |
652 | 15 | netbios_heur_subdissector_list = find_heur_dissector_list("netbios"); |
653 | 15 | } |
654 | | |
655 | | /* |
656 | | * Microsoft appear to have something they call "direct hosting", where |
657 | | * SMB - and, I infer, related stuff, such as name resolution - runs |
658 | | * directly over IPX. (In Windows 2000, they also run SMB directly over |
659 | | * TCP, on port 445, and that also appears to be called "direct hosting". |
660 | | * Wireshark handles SMB-over-TCP.) |
661 | | * |
662 | | * The document at |
663 | | * |
664 | | * http://support.microsoft.com/support/kb/articles/q203/0/51.asp |
665 | | * |
666 | | * speaks of NMPI - the "Name Management Protocol on IPX" - as being |
667 | | * "Microsoft's protocol for name management support when you use IPX |
668 | | * without the NetBIOS interface," and says that "This process of routing |
669 | | * the SMB protocol directly through IPX is known as Direct Hosting." |
670 | | * |
671 | | * It speaks of IPX socket 0x551 as being for NMPI; we define it as |
672 | | * IPX_SOCKET_NWLINK_SMB_NAMEQUERY. |
673 | | * |
674 | | * We also define IPX_SOCKET_NWLINK_SMB_DGRAM as 0x0553 and define |
675 | | * IPX_SOCKET_NWLINK_SMB_BROWSE as 0x0555 (with a "? not sure on this" |
676 | | * comment after the latter one). |
677 | | * |
678 | | * We have seen at least some browser announcements on IPX socket 0x553; |
679 | | * those are WAN broadcast packets, complete with 8 IPX network |
680 | | * numbers, and with the header containing the usual two NetBIOS names |
681 | | * that show up in NetBIOS datagrams. |
682 | | * |
683 | | * Network Monitor calls those packets NMPI packets, even though they're |
684 | | * on socket 0x553, not socket 0x551, and contain SMB datagrams, not name |
685 | | * resolution packets. |
686 | | * |
687 | | * At least some of this is discussed in the "SMBPUB.DOC" Word document |
688 | | * stored in |
689 | | * |
690 | | * ftp://ftp.microsoft.com/developr/drg/CIFS/smbpub.zip |
691 | | * |
692 | | * which can also be found in text form at |
693 | | * |
694 | | * http://www.samba.org/samba/ftp/specs/smbpub.txt |
695 | | * |
696 | | * which says that for "connectionless IPX transport" the sockets that |
697 | | * are used are: |
698 | | * |
699 | | * SMB_SERVER_SOCKET (0x550) - SMB requests from clients |
700 | | * SMB_NAME_SOCKET (0x551) - name claims and name query messages |
701 | | * REDIR_SOCKET (0x552) - used by the redirector (client) for |
702 | | * sending SMB requests and receiving SMB replies |
703 | | * MAILSLOT_SOCKET (0x553) - used by the redirector and browser |
704 | | * for mailslot datagrams |
705 | | * MESSENGER_SOCKET (0x554) - used by the redirector to send |
706 | | * messages from client to client |
707 | | * |
708 | | * Name claim/query packets, and mailslot datagrams, are: |
709 | | * |
710 | | * 8 IPX network addresses |
711 | | * 1 byte of opcode |
712 | | * 1 byte of name type |
713 | | * 2 bytes of message ID |
714 | | * 16 bytes of name being sought or claimed |
715 | | * 16 bytes of requesting machine |
716 | | * |
717 | | * The opcode is one of: |
718 | | * |
719 | | * INAME_CLAIM (0xf1) - server name claim message |
720 | | * INAME_DELETE (0xf2) - relinquish server name |
721 | | * INAME_QUERY (0xf3) - locate server name |
722 | | * INAME_FOUND (0xf4) - response to INAME_QUERY |
723 | | * IMSG_HANGUP (0xf5) - messenger hangup |
724 | | * IMSLOT_SEND (0xfc) - mailslot write |
725 | | * IMSLOT_FIND (0xfd) - find name for mailslot write |
726 | | * IMSLOT_NAME (0xfe) - response to IMSLOT_FIND |
727 | | * |
728 | | * The name type is one of: |
729 | | * |
730 | | * INTYPE_MACHINE 1 |
731 | | * INTYPE_WKGROUP 2 |
732 | | * INTYPE_BROWSER 3 |
733 | | */ |
734 | | static int proto_nmpi; |
735 | | |
736 | | static int ett_nmpi; |
737 | | static int ett_nmpi_name_type_flags; |
738 | | |
739 | | |
740 | | static int |
741 | | dissect_nmpi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
742 | 108 | { |
743 | 108 | proto_tree *nmpi_tree = NULL; |
744 | 108 | proto_item *ti; |
745 | 108 | int offset = 0; |
746 | 108 | uint8_t opcode; |
747 | 108 | char name[(NETBIOS_NAME_LEN - 1)*4 + 1]; |
748 | 108 | int name_type; |
749 | 108 | char node_name[(NETBIOS_NAME_LEN - 1)*4 + 1]; |
750 | | /*int node_name_type = 0;*/ |
751 | 108 | tvbuff_t *next_tvb; |
752 | | |
753 | 108 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "NMPI"); |
754 | 108 | col_clear(pinfo->cinfo, COL_INFO); |
755 | | |
756 | 108 | if (tree) { |
757 | 108 | ti = proto_tree_add_item(tree, proto_nmpi, tvb, offset, 68, |
758 | 108 | ENC_NA); |
759 | 108 | nmpi_tree = proto_item_add_subtree(ti, ett_nmpi); |
760 | | |
761 | 108 | add_routers(nmpi_tree, tvb, offset); |
762 | 108 | } |
763 | 108 | offset += 32; |
764 | | |
765 | | /* |
766 | | * XXX - we don't use "node_name" or "node_name_type". |
767 | | */ |
768 | 108 | opcode = tvb_get_uint8(tvb, offset); |
769 | 108 | name_type = get_netbios_name(tvb, offset+4, name, (NETBIOS_NAME_LEN - 1)*4 + 1); |
770 | 108 | /*node_name_type = */get_netbios_name(tvb, offset+20, node_name, (NETBIOS_NAME_LEN - 1)*4 + 1); |
771 | | |
772 | 108 | switch (opcode) { |
773 | | |
774 | 0 | case INAME_CLAIM: |
775 | 0 | col_add_fstr(pinfo->cinfo, COL_INFO, "Claim name %s<%02x>", |
776 | 0 | name, name_type); |
777 | 0 | break; |
778 | | |
779 | 1 | case INAME_DELETE: |
780 | 1 | col_add_fstr(pinfo->cinfo, COL_INFO, "Delete name %s<%02x>", |
781 | 1 | name, name_type); |
782 | 1 | break; |
783 | | |
784 | 1 | case INAME_QUERY: |
785 | 1 | col_add_fstr(pinfo->cinfo, COL_INFO, "Query name %s<%02x>", |
786 | 1 | name, name_type); |
787 | 1 | break; |
788 | | |
789 | 1 | case INAME_FOUND: |
790 | 1 | col_add_fstr(pinfo->cinfo, COL_INFO, "Name %s<%02x> found", |
791 | 1 | name, name_type); |
792 | 1 | break; |
793 | | |
794 | 2 | case IMSG_HANGUP: |
795 | 2 | col_add_fstr(pinfo->cinfo, COL_INFO, |
796 | 2 | "Messenger hangup on %s<%02x>", name, name_type); |
797 | 2 | break; |
798 | | |
799 | 3 | case IMSLOT_SEND: |
800 | 3 | col_add_fstr(pinfo->cinfo, COL_INFO, |
801 | 3 | "Mailslot write to %s<%02x>", name, name_type); |
802 | 3 | break; |
803 | | |
804 | 1 | case IMSLOT_FIND: |
805 | 1 | col_add_fstr(pinfo->cinfo, COL_INFO, |
806 | 1 | "Find mailslot name %s<%02x>", name, name_type); |
807 | 1 | break; |
808 | | |
809 | 6 | case IMSLOT_NAME: |
810 | 6 | col_add_fstr(pinfo->cinfo, COL_INFO, |
811 | 6 | "Mailslot name %s<%02x> found", name, name_type); |
812 | 6 | break; |
813 | | |
814 | 36 | default: |
815 | 36 | col_add_fstr(pinfo->cinfo, COL_INFO, |
816 | 36 | "Unknown NMPI op 0x%02x: name %s<%02x>", |
817 | 36 | opcode, name, name_type); |
818 | 36 | break; |
819 | 108 | } |
820 | | |
821 | 51 | if (tree) { |
822 | 51 | proto_tree_add_item(nmpi_tree, hf_nbipx_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
823 | 51 | proto_tree_add_item(nmpi_tree, hf_nbipx_name_type, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
824 | 51 | proto_tree_add_item(nmpi_tree, hf_nbipx_messageid, tvb, offset+2, 2, ENC_LITTLE_ENDIAN); |
825 | 51 | netbios_add_name("Requested name", tvb, offset+4, nmpi_tree); |
826 | 51 | netbios_add_name("Source name", tvb, offset+20, nmpi_tree); |
827 | 51 | } |
828 | | |
829 | 51 | offset += 1 + 1 + 2 + NETBIOS_NAME_LEN + NETBIOS_NAME_LEN; |
830 | | |
831 | 51 | if (opcode == IMSLOT_SEND && tvb_offset_exists(tvb, offset)) { |
832 | 3 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
833 | 3 | dissect_netbios_payload(next_tvb, pinfo, tree); |
834 | 3 | } |
835 | 51 | return tvb_captured_length(tvb); |
836 | 108 | } |
837 | | |
838 | | void |
839 | | proto_register_nmpi(void) |
840 | 15 | { |
841 | | /* |
842 | | static hf_register_info hf[] = { |
843 | | { &variable, |
844 | | { "Name", "nmpi.abbreviation", TYPE, VALS_POINTER }}, |
845 | | }; */ |
846 | 15 | static int *ett[] = { |
847 | 15 | &ett_nmpi, |
848 | 15 | &ett_nmpi_name_type_flags, |
849 | 15 | }; |
850 | | |
851 | 15 | proto_nmpi = proto_register_protocol("Name Management Protocol over IPX", |
852 | 15 | "NMPI", "nmpi"); |
853 | | /* proto_register_field_array(proto_nmpi, hf, array_length(hf));*/ |
854 | 15 | proto_register_subtree_array(ett, array_length(ett)); |
855 | | |
856 | 15 | nmpi_handle = register_dissector("nmpi", dissect_nmpi, proto_nmpi); |
857 | 15 | } |
858 | | |
859 | | void |
860 | | proto_reg_handoff_nmpi(void) |
861 | 15 | { |
862 | 15 | dissector_add_uint("ipx.socket", IPX_SOCKET_NWLINK_SMB_NAMEQUERY, |
863 | 15 | nmpi_handle); |
864 | 15 | dissector_add_uint("ipx.socket", IPX_SOCKET_NWLINK_SMB_MAILSLOT, |
865 | 15 | nmpi_handle); |
866 | 15 | } |
867 | | |
868 | | /* |
869 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
870 | | * |
871 | | * Local variables: |
872 | | * c-basic-offset: 8 |
873 | | * tab-width: 8 |
874 | | * indent-tabs-mode: t |
875 | | * End: |
876 | | * |
877 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
878 | | * :indentSize=8:tabSize=8:noTabs=false: |
879 | | */ |