/src/wireshark/epan/dissectors/packet-nbt.c
Line | Count | Source |
1 | | /* packet-nbt.c |
2 | | * Routines for NetBIOS-over-TCP packet disassembly |
3 | | * Guy Harris <guy@alum.mit.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/expert.h> |
16 | | #include <epan/exceptions.h> |
17 | | #include <epan/prefs.h> |
18 | | #include <epan/show_exception.h> |
19 | | #include <epan/to_str.h> |
20 | | #include <epan/charsets.h> |
21 | | #include <epan/tfs.h> |
22 | | #include <epan/unit_strings.h> |
23 | | |
24 | | #include <wsutil/array.h> |
25 | | #include <wsutil/str_util.h> |
26 | | |
27 | | #include "packet-dns.h" |
28 | | #include "packet-netbios.h" |
29 | | #include "packet-tcp.h" |
30 | | |
31 | | void proto_register_nbt(void); |
32 | | void proto_reg_handoff_nbt(void); |
33 | | |
34 | | static dissector_handle_t nbns_handle, nbdgm_handle, nbss_handle; |
35 | | |
36 | | static int proto_nbns; |
37 | | static int hf_nbns_flags; |
38 | | static int hf_nbns_flags_response; |
39 | | static int hf_nbns_flags_opcode; |
40 | | static int hf_nbns_flags_authoritative; |
41 | | static int hf_nbns_flags_truncated; |
42 | | static int hf_nbns_flags_recdesired; |
43 | | static int hf_nbns_flags_recavail; |
44 | | static int hf_nbns_flags_broadcast; |
45 | | static int hf_nbns_flags_rcode; |
46 | | static int hf_nbns_transaction_id; |
47 | | static int hf_nbns_count_questions; |
48 | | static int hf_nbns_count_answers; |
49 | | static int hf_nbns_count_auth_rr; |
50 | | static int hf_nbns_count_add_rr; |
51 | | static int hf_nbns_name_flags; |
52 | | static int hf_nbns_name_flags_group; |
53 | | static int hf_nbns_name_flags_ont; |
54 | | static int hf_nbns_name_flags_drg; |
55 | | static int hf_nbns_name_flags_cnf; |
56 | | static int hf_nbns_name_flags_act; |
57 | | static int hf_nbns_name_flags_prm; |
58 | | static int hf_nbns_nb_flags; |
59 | | static int hf_nbns_nb_flags_group; |
60 | | static int hf_nbns_nb_flags_ont; |
61 | | static int hf_nbns_name; |
62 | | static int hf_nbns_type; |
63 | | static int hf_nbns_class; |
64 | | |
65 | | /* Generated from convert_proto_tree_add_text.pl */ |
66 | | static int hf_nbns_num_alignment_errors; |
67 | | static int hf_nbns_data; |
68 | | static int hf_nbns_unit_id; |
69 | | static int hf_nbns_num_command_blocks; |
70 | | static int hf_nbns_num_retransmits; |
71 | | static int hf_nbns_period_of_statistics; |
72 | | static int hf_nbns_addr; |
73 | | static int hf_nbns_test_result; |
74 | | static int hf_nbns_num_pending_sessions; |
75 | | static int hf_nbns_num_no_resource_conditions; |
76 | | static int hf_nbns_session_data_packet_size; |
77 | | static int hf_nbns_version_number; |
78 | | static int hf_nbns_max_num_pending_sessions; |
79 | | static int hf_nbns_num_collisions; |
80 | | static int hf_nbns_num_good_sends; |
81 | | static int hf_nbns_num_send_aborts; |
82 | | static int hf_nbns_number_of_names; |
83 | | static int hf_nbns_num_crcs; |
84 | | static int hf_nbns_num_good_receives; |
85 | | static int hf_nbns_max_total_sessions_possible; |
86 | | static int hf_nbns_jumpers; |
87 | | static int hf_nbns_netbios_name; |
88 | | static int hf_nbns_ttl; |
89 | | static int hf_nbns_data_length; |
90 | | |
91 | | static int ett_nbns; |
92 | | static int ett_nbns_qd; |
93 | | static int ett_nbns_flags; |
94 | | static int ett_nbns_nb_flags; |
95 | | static int ett_nbns_name_flags; |
96 | | static int ett_nbns_rr; |
97 | | static int ett_nbns_qry; |
98 | | static int ett_nbns_ans; |
99 | | |
100 | | static expert_field ei_nbns_incomplete_entry; |
101 | | |
102 | | static int proto_nbdgm; |
103 | | static int hf_nbdgm_type; |
104 | | static int hf_nbdgm_flags; |
105 | | static int hf_nbdgm_fragment; |
106 | | static int hf_nbdgm_first; |
107 | | static int hf_nbdgm_node_type; |
108 | | static int hf_nbdgm_datagram_id; |
109 | | static int hf_nbdgm_src_ip; |
110 | | static int hf_nbdgm_src_port; |
111 | | static int hf_nbdgm_datagram_length; |
112 | | static int hf_nbdgm_packet_offset; |
113 | | static int hf_nbdgm_error_code; |
114 | | static int hf_nbdgm_source_name; |
115 | | static int hf_nbdgm_destination_name; |
116 | | |
117 | | static int ett_nbdgm; |
118 | | static int ett_nbdgm_flags; |
119 | | |
120 | | static int proto_nbss; |
121 | | static int hf_nbss_type; |
122 | | static int hf_nbss_flags; |
123 | | static int hf_nbss_flags_e; |
124 | | static int hf_nbss_length; |
125 | | static int hf_nbss_cifs_length; |
126 | | static int hf_nbss_error_code; |
127 | | static int hf_nbss_retarget_ip_address; |
128 | | static int hf_nbss_retarget_port; |
129 | | static int hf_nbss_continuation_data; |
130 | | static int hf_nbss_called_name; |
131 | | static int hf_nbss_calling_name; |
132 | | |
133 | | static int ett_nbss; |
134 | | static int ett_nbss_flags; |
135 | | |
136 | | /* desegmentation of NBSS over TCP */ |
137 | | static bool nbss_desegment = true; |
138 | | |
139 | | /* See RFC 1001 and 1002 for information on the first three, and see |
140 | | |
141 | | http://www.cifs.com/specs/draft-leach-cifs-v1-spec-01.txt |
142 | | |
143 | | Appendix B, and various messages on the CIFS mailing list such as |
144 | | |
145 | | http://discuss.microsoft.com/SCRIPTS/WA-MSD.EXE?A2=ind9811A&L=cifs&P=R386 |
146 | | |
147 | | for information on the fourth. */ |
148 | 15 | #define UDP_PORT_NBNS 137 |
149 | 15 | #define UDP_PORT_NBDGM 138 |
150 | | #define TCP_PORT_NBSS 139 |
151 | 14 | #define TCP_PORT_CIFS 445 |
152 | 15 | #define TCP_NBSS_PORT_RANGE "139,445" |
153 | | |
154 | | /* Packet structure taken from RFC 1002. See also RFC 1001. |
155 | | * Opcode, flags, and rcode treated as "flags", similarly to DNS, |
156 | | * to make it easier to lift the dissection code from "packet-dns.c". */ |
157 | | |
158 | | /* Offsets of fields in the NBNS header. */ |
159 | 184 | #define NBNS_ID 0 |
160 | 184 | #define NBNS_FLAGS 2 |
161 | 92 | #define NBNS_QUEST 4 |
162 | 92 | #define NBNS_ANS 6 |
163 | 92 | #define NBNS_AUTH 8 |
164 | 92 | #define NBNS_ADD 10 |
165 | | |
166 | | /* Length of NBNS header. */ |
167 | 92 | #define NBNS_HDRLEN 12 |
168 | | |
169 | | /* type values */ |
170 | 12 | #define T_NB 32 /* NetBIOS name service RR */ |
171 | 38 | #define T_NBSTAT 33 /* NetBIOS node status RR */ |
172 | | |
173 | | /* Bit fields in the flags */ |
174 | 360 | #define F_RESPONSE (1<<15) /* packet is response */ |
175 | 107 | #define F_OPCODE (0xF<<11) /* query opcode */ |
176 | 92 | #define OPCODE_SHIFT 11 |
177 | 15 | #define F_AUTHORITATIVE (1<<10) /* response is authoritative */ |
178 | 15 | #define F_TRUNCATED (1<<9) /* response is truncated */ |
179 | 15 | #define F_RECDESIRED (1<<8) /* recursion desired */ |
180 | 15 | #define F_RECAVAIL (1<<7) /* recursion available */ |
181 | 15 | #define F_BROADCAST (1<<4) /* broadcast/multicast packet */ |
182 | 15 | #define F_RCODE (0xF<<0) /* reply code */ |
183 | | |
184 | | static const true_false_string tfs_flags_response = { |
185 | | "Message is a response", |
186 | | "Message is a query" |
187 | | }; |
188 | | |
189 | | static const true_false_string tfs_flags_authoritative = { |
190 | | "Server is an authority for domain", |
191 | | "Server is not an authority for domain" |
192 | | }; |
193 | | |
194 | | static const true_false_string tfs_flags_truncated = { |
195 | | "Message is truncated", |
196 | | "Message is not truncated" |
197 | | }; |
198 | | |
199 | | static const true_false_string tfs_flags_recdesired = { |
200 | | "Do query recursively", |
201 | | "Don't do query recursively" |
202 | | }; |
203 | | |
204 | | static const true_false_string tfs_flags_recavail = { |
205 | | "Server can do recursive queries", |
206 | | "Server can't do recursive queries" |
207 | | }; |
208 | | |
209 | | static const true_false_string tfs_flags_broadcast = { |
210 | | "Broadcast packet", |
211 | | "Not a broadcast packet" |
212 | | }; |
213 | | |
214 | | static const true_false_string tfs_nbss_flags_e = { |
215 | | "Add 65536 to length", |
216 | | "Add 0 to length" |
217 | | }; |
218 | | |
219 | | /* Opcodes */ |
220 | | #define OPCODE_QUERY 0 /* standard query */ |
221 | | #define OPCODE_REGISTRATION 5 /* registration */ |
222 | | #define OPCODE_RELEASE 6 /* release name */ |
223 | 326 | #define OPCODE_WACK 7 /* wait for acknowledgement */ |
224 | | #define OPCODE_REFRESH 8 /* refresh registration */ |
225 | | #define OPCODE_REFRESHALT 9 /* refresh registration (alternate opcode) */ |
226 | | #define OPCODE_MHREGISTRATION 15 /* multi-homed registration */ |
227 | | |
228 | | static const value_string opcode_vals[] = { |
229 | | { OPCODE_QUERY, "Name query" }, |
230 | | { OPCODE_REGISTRATION, "Registration" }, |
231 | | { OPCODE_RELEASE, "Release" }, |
232 | | { OPCODE_WACK, "Wait for acknowledgment" }, |
233 | | { OPCODE_REFRESH, "Refresh" }, |
234 | | { OPCODE_REFRESHALT, "Refresh (alternate opcode)" }, |
235 | | { OPCODE_MHREGISTRATION, "Multi-homed registration" }, |
236 | | { 0, NULL } |
237 | | }; |
238 | | |
239 | | /* Reply codes */ |
240 | | #define RCODE_NOERROR 0 |
241 | | #define RCODE_FMTERROR 1 |
242 | | #define RCODE_SERVFAIL 2 |
243 | | #define RCODE_NAMEERROR 3 |
244 | | #define RCODE_NOTIMPL 4 |
245 | | #define RCODE_REFUSED 5 |
246 | | #define RCODE_ACTIVE 6 |
247 | | #define RCODE_CONFLICT 7 |
248 | | |
249 | | static const value_string rcode_vals[] = { |
250 | | { RCODE_NOERROR, "No error" }, |
251 | | { RCODE_FMTERROR, "Request was invalidly formatted" }, |
252 | | { RCODE_SERVFAIL, "Server failure" }, |
253 | | { RCODE_NAMEERROR, "Requested name does not exist" }, |
254 | | { RCODE_NOTIMPL, "Request is not implemented" }, |
255 | | { RCODE_REFUSED, "Request was refused" }, |
256 | | { RCODE_ACTIVE, "Name is owned by another node" }, |
257 | | { RCODE_CONFLICT, "Name is in conflict" }, |
258 | | { 0, NULL } |
259 | | }; |
260 | | |
261 | | /* Values for the "NB_FLAGS" field of RR data. From RFC 1001 and 1002, |
262 | | * except for NB_FLAGS_ONT_H_NODE, which was discovered by looking at |
263 | | * packet traces. */ |
264 | 231 | #define NB_FLAGS_ONT (3<<(15-2)) /* bits for node type */ |
265 | | #define NB_FLAGS_ONT_B_NODE (0<<(15-2)) /* B-mode node */ |
266 | | #define NB_FLAGS_ONT_P_NODE (1<<(15-2)) /* P-mode node */ |
267 | | #define NB_FLAGS_ONT_M_NODE (2<<(15-2)) /* M-mode node */ |
268 | | #define NB_FLAGS_ONT_H_NODE (3<<(15-2)) /* H-mode node */ |
269 | | |
270 | 231 | #define NB_FLAGS_G (1<<(15-0)) /* group name */ |
271 | | |
272 | | /* Values for the "NAME_FLAGS" field of a NODE_NAME entry in T_NBSTAT |
273 | | * RR data. From RFC 1001 and 1002; as I remember, the "NAME_FLAGS" |
274 | | * field doesn't include any special values for H-mode nodes, even |
275 | | * though one can register them (if so, perhaps that was done to |
276 | | * avoid surprising clients that don't know about H-mode nodes). */ |
277 | 15 | #define NAME_FLAGS_PRM (1<<(15-6)) /* name is permanent node name */ |
278 | | |
279 | 15 | #define NAME_FLAGS_ACT (1<<(15-5)) /* name is active */ |
280 | | |
281 | 15 | #define NAME_FLAGS_CNF (1<<(15-4)) /* name is in conflict */ |
282 | | |
283 | 15 | #define NAME_FLAGS_DRG (1<<(15-3)) /* name is being deregistered */ |
284 | | |
285 | 15 | #define NAME_FLAGS_ONT (3<<(15-2)) /* bits for node type */ |
286 | | #define NAME_FLAGS_ONT_B_NODE (0<<(15-2)) /* B-mode node */ |
287 | | #define NAME_FLAGS_ONT_P_NODE (1<<(15-2)) /* P-mode node */ |
288 | | #define NAME_FLAGS_ONT_M_NODE (2<<(15-2)) /* M-mode node */ |
289 | | |
290 | 15 | #define NAME_FLAGS_G (1<<(15-0)) /* group name */ |
291 | | |
292 | | static const value_string name_flags_ont_vals[] = { |
293 | | { NAME_FLAGS_ONT_B_NODE, "B-node" }, |
294 | | { NAME_FLAGS_ONT_P_NODE, "P-node" }, |
295 | | { NAME_FLAGS_ONT_M_NODE, "M-node" }, |
296 | | { 0, NULL } |
297 | | }; |
298 | | |
299 | | static const value_string nb_flags_ont_vals[] = { |
300 | | { NB_FLAGS_ONT_B_NODE, "B-node" }, |
301 | | { NB_FLAGS_ONT_P_NODE, "P-node" }, |
302 | | { NB_FLAGS_ONT_M_NODE, "M-node" }, |
303 | | { NB_FLAGS_ONT_H_NODE, "H-node" }, |
304 | | { 0, NULL } |
305 | | }; |
306 | | |
307 | | static const value_string nb_type_name_vals[] = { |
308 | | { T_NB, "NB" }, |
309 | | { T_NBSTAT, "NBSTAT" }, |
310 | | { 0, NULL } |
311 | | }; |
312 | | |
313 | 428 | #define NBNAME_BUF_LEN 128 |
314 | | |
315 | | static void |
316 | | add_rr_to_tree(proto_tree *rr_tree, packet_info *pinfo, tvbuff_t *tvb, int offset, |
317 | | const char *name, int namelen, |
318 | | int type, int class_val, |
319 | | unsigned ttl, uint16_t data_len) |
320 | 150 | { |
321 | 150 | proto_tree_add_string(rr_tree, hf_nbns_name, tvb, offset+1, namelen-1, name); |
322 | 150 | offset += namelen; |
323 | 150 | proto_tree_add_uint(rr_tree, hf_nbns_type, tvb, offset, 2, type); |
324 | 150 | offset += 2; |
325 | 150 | proto_tree_add_uint(rr_tree, hf_nbns_class, tvb, offset, 2, class_val); |
326 | 150 | offset += 2; |
327 | 150 | proto_tree_add_uint_format_value(rr_tree, hf_nbns_ttl, tvb, offset, 4, ttl, "%s", |
328 | 150 | signed_time_secs_to_str(pinfo->pool, ttl)); |
329 | 150 | offset += 4; |
330 | 150 | proto_tree_add_uint(rr_tree, hf_nbns_data_length, tvb, offset, 2, data_len); |
331 | 150 | } |
332 | | |
333 | | static int |
334 | | get_nbns_name(tvbuff_t *tvb, wmem_allocator_t* allocator, int offset, int nbns_data_offset, |
335 | | char *name_ret, int name_ret_len, int *name_type_ret) |
336 | 428 | { |
337 | 428 | int name_len; |
338 | 428 | const char *name; |
339 | 428 | const char *nbname; |
340 | 428 | char *nbname_buf; |
341 | 428 | const char *pname; |
342 | 428 | char cname, cnbname; |
343 | 428 | int name_type; |
344 | 428 | char *pname_ret; |
345 | 428 | size_t idx = 0; |
346 | 428 | unsigned used_bytes; |
347 | | |
348 | 428 | nbname_buf = (char *)wmem_alloc(allocator, NBNAME_BUF_LEN); |
349 | 428 | nbname = nbname_buf; |
350 | 428 | used_bytes = get_dns_name(allocator, tvb, offset, 0, nbns_data_offset, &name, &name_len); |
351 | | |
352 | | /* OK, now undo the first-level encoding. */ |
353 | 428 | pname = &name[0]; |
354 | 428 | pname_ret = name_ret; |
355 | | |
356 | 428 | for (;;) { |
357 | | /* Every two characters of the first level-encoded name |
358 | | * turn into one character in the decoded name. */ |
359 | 399 | cname = *pname; |
360 | 399 | if (cname == '\0') |
361 | 8 | break; /* no more characters */ |
362 | 391 | if (cname == '.') |
363 | 0 | break; /* scope ID follows */ |
364 | 391 | if (cname < 'A' || cname > 'Z') { |
365 | | /* Not legal. */ |
366 | 383 | nbname = "Illegal NetBIOS name (1st character not between A and Z in first-level encoding)"; |
367 | 383 | goto bad; |
368 | 383 | } |
369 | 8 | cname -= 'A'; |
370 | 8 | cnbname = cname << 4; |
371 | 8 | pname++; |
372 | | |
373 | 8 | cname = *pname; |
374 | 8 | if (cname == '\0' || cname == '.') { |
375 | | /* No more characters in the name - but we're in |
376 | | * the middle of a pair. Not legal. */ |
377 | 1 | nbname = "Illegal NetBIOS name (odd number of bytes)"; |
378 | 1 | goto bad; |
379 | 1 | } |
380 | 7 | if (cname < 'A' || cname > 'Z') { |
381 | | /* Not legal. */ |
382 | 3 | nbname = "Illegal NetBIOS name (2nd character not between A and Z in first-level encoding)"; |
383 | 3 | goto bad; |
384 | 3 | } |
385 | 4 | cname -= 'A'; |
386 | 4 | cnbname |= cname; |
387 | 4 | pname++; |
388 | | |
389 | | /* Do we have room to store the character? */ |
390 | 4 | if (idx < NETBIOS_NAME_LEN) { |
391 | | /* Yes - store the character. */ |
392 | 4 | nbname_buf[idx++] = cnbname; |
393 | 4 | } |
394 | 4 | } |
395 | | |
396 | | /* NetBIOS names are supposed to be exactly 16 bytes long. */ |
397 | 41 | if (idx != NETBIOS_NAME_LEN) { |
398 | | /* It's not. */ |
399 | 8 | snprintf(nbname_buf, NBNAME_BUF_LEN, "Illegal NetBIOS name (%lu bytes long)", |
400 | 8 | (unsigned long)idx); |
401 | 8 | goto bad; |
402 | 8 | } |
403 | | |
404 | | /* This one is; make its name printable. */ |
405 | 33 | name_type = process_netbios_name((const uint8_t*)nbname, name_ret, name_ret_len); |
406 | 33 | pname_ret += MIN(strlen(name_ret), (size_t) name_ret_len); |
407 | 33 | snprintf(pname_ret, name_ret_len-(pname_ret-name_ret), "<%02x>", name_type); |
408 | 33 | if (cname == '.') { |
409 | | /* We have a scope ID, starting at "pname"; append that to |
410 | | * the decoded host name. */ |
411 | | /* RFC 1001 says that scope IDs "meet the restricted character set |
412 | | * of the domain system and has a leading period." Convert it from |
413 | | * ASCII before appending it to our NBName, so we have a valid |
414 | | * UTF-8 string. |
415 | | */ |
416 | 0 | const char* scope_id = (char*)get_ascii_string(allocator, (const uint8_t*)pname, strlen(pname)); |
417 | 0 | int bytes_attempted = (int)g_strlcat(name_ret, scope_id, name_ret_len); |
418 | 0 | if (bytes_attempted >= name_ret_len) { |
419 | 0 | ws_utf8_truncate(name_ret, name_ret_len - 1); |
420 | 0 | } |
421 | 0 | } |
422 | 33 | if (name_type_ret != NULL) |
423 | 0 | *name_type_ret = name_type; |
424 | 33 | return used_bytes; |
425 | | |
426 | 395 | bad: |
427 | 395 | if (name_type_ret != NULL) |
428 | 395 | *name_type_ret = -1; |
429 | | /* This is only valid because nbname is always assigned an error string |
430 | | * before jumping to bad: Otherwise nbname wouldn't be \0 terminated */ |
431 | 395 | snprintf(pname_ret, name_ret_len-(pname_ret-name_ret), "%s", nbname); |
432 | 395 | return used_bytes; |
433 | 41 | } |
434 | | |
435 | | |
436 | | static int |
437 | | get_nbns_name_type_class(tvbuff_t *tvb, wmem_allocator_t* allocator, int offset, int nbns_data_offset, |
438 | | char *name_ret, int *name_len_ret, int *name_type_ret, |
439 | | int *type_ret, int *class_ret) |
440 | 284 | { |
441 | 284 | int name_len; |
442 | 284 | int type; |
443 | 284 | int rr_class; |
444 | | |
445 | 284 | name_len = get_nbns_name(tvb, allocator, offset, nbns_data_offset, name_ret, |
446 | 284 | *name_len_ret, name_type_ret); |
447 | 284 | offset += name_len; |
448 | | |
449 | 284 | type = tvb_get_ntohs(tvb, offset); |
450 | 284 | offset += 2; |
451 | | |
452 | 284 | rr_class = tvb_get_ntohs(tvb, offset); |
453 | | |
454 | 284 | *type_ret = type; |
455 | 284 | *class_ret = rr_class; |
456 | 284 | *name_len_ret = name_len; |
457 | | |
458 | 284 | return name_len + 4; |
459 | 284 | } |
460 | | |
461 | | static void |
462 | | add_name_and_type(proto_tree *tree, tvbuff_t *tvb, int offset, int len, |
463 | | int hf_tag, const char *name, int name_type) |
464 | 238 | { |
465 | 238 | if (name_type != -1) { |
466 | 0 | proto_tree_add_string_format_value(tree, hf_tag, tvb, offset, len, name, "%s (%s)", |
467 | 0 | name, netbios_name_type_descr(name_type)); |
468 | 238 | } else { |
469 | 238 | proto_tree_add_string(tree, hf_tag, tvb, offset, len, name); |
470 | 238 | } |
471 | 238 | } |
472 | | |
473 | 1.05k | #define MAX_NAME_LEN (NETBIOS_NAME_LEN - 1)*4 + MAX_DNAME_LEN + 64 |
474 | | |
475 | | static int |
476 | | dissect_nbns_query(tvbuff_t *tvb, packet_info* pinfo, int offset, int nbns_data_offset, |
477 | | proto_tree *nbns_tree, bool add_column_data) |
478 | 115 | { |
479 | 115 | int len; |
480 | 115 | char *name; |
481 | 115 | int name_len; |
482 | 115 | int name_type; |
483 | 115 | int type; |
484 | 115 | int dns_class; |
485 | 115 | const char *type_name; |
486 | 115 | int data_offset; |
487 | 115 | int data_start; |
488 | 115 | proto_tree *q_tree; |
489 | | |
490 | 115 | name = (char *)wmem_alloc(pinfo->pool, MAX_NAME_LEN); |
491 | 115 | data_start = data_offset = offset; |
492 | | |
493 | 115 | name_len = MAX_NAME_LEN; |
494 | 115 | len = get_nbns_name_type_class(tvb, pinfo->pool, offset, nbns_data_offset, name, |
495 | 115 | &name_len, &name_type, &type, &dns_class); |
496 | 115 | data_offset += len; |
497 | | |
498 | 115 | type_name = val_to_str_const(type, nb_type_name_vals, "Unknown"); |
499 | | |
500 | 115 | if (add_column_data) |
501 | 45 | col_append_fstr(pinfo->cinfo, COL_INFO, " %s %s", type_name, name); |
502 | | |
503 | 115 | if (nbns_tree != NULL) { |
504 | 96 | q_tree = proto_tree_add_subtree_format(nbns_tree, tvb, offset, len, |
505 | 96 | ett_nbns_qd, NULL, "%s: type %s, class %s", name, type_name, |
506 | 96 | val_to_str_const(dns_class, dns_classes, "Unknown")); |
507 | | |
508 | 96 | add_name_and_type(q_tree, tvb, offset, name_len, hf_nbns_name, name, |
509 | 96 | name_type); |
510 | 96 | offset += name_len; |
511 | | |
512 | 96 | proto_tree_add_uint(q_tree, hf_nbns_type, tvb, offset, 2, type); |
513 | 96 | offset += 2; |
514 | | |
515 | 96 | proto_tree_add_uint(q_tree, hf_nbns_class, tvb, offset, 2, dns_class); |
516 | | /*offset += 2;*/ |
517 | 96 | } |
518 | | |
519 | 115 | return data_offset - data_start; |
520 | 115 | } |
521 | | |
522 | | static void |
523 | | nbns_add_nbns_flags(column_info *cinfo, proto_tree *nbns_tree, tvbuff_t *tvb, int offset, int is_wack) |
524 | 201 | { |
525 | 201 | uint16_t flag; |
526 | 201 | static int * const req_flags[] = { |
527 | 201 | &hf_nbns_flags_response, |
528 | 201 | &hf_nbns_flags_opcode, |
529 | 201 | &hf_nbns_flags_truncated, |
530 | 201 | &hf_nbns_flags_recdesired, |
531 | 201 | &hf_nbns_flags_broadcast, |
532 | 201 | NULL |
533 | 201 | }; |
534 | | |
535 | 201 | static int * const resp_flags[] = { |
536 | 201 | &hf_nbns_flags_response, |
537 | 201 | &hf_nbns_flags_opcode, |
538 | 201 | &hf_nbns_flags_authoritative, |
539 | 201 | &hf_nbns_flags_truncated, |
540 | 201 | &hf_nbns_flags_recdesired, |
541 | 201 | &hf_nbns_flags_recavail, |
542 | 201 | &hf_nbns_flags_broadcast, |
543 | 201 | &hf_nbns_flags_rcode, |
544 | 201 | NULL |
545 | 201 | }; |
546 | | |
547 | 201 | static int * const resp_wack_flags[] = { |
548 | 201 | &hf_nbns_flags_response, |
549 | 201 | &hf_nbns_flags_opcode, |
550 | 201 | &hf_nbns_flags_authoritative, |
551 | 201 | &hf_nbns_flags_truncated, |
552 | 201 | &hf_nbns_flags_recdesired, |
553 | 201 | &hf_nbns_flags_recavail, |
554 | 201 | &hf_nbns_flags_broadcast, |
555 | 201 | NULL |
556 | 201 | }; |
557 | | |
558 | 201 | flag = tvb_get_ntohs(tvb, offset); |
559 | 201 | if (cinfo) { |
560 | 0 | if (flag & F_RESPONSE && !is_wack) { |
561 | 0 | if ((flag & F_RCODE)) |
562 | 0 | col_append_fstr(cinfo, COL_INFO, ", %s", |
563 | 0 | val_to_str_const(flag & F_RCODE, rcode_vals, |
564 | 0 | "Unknown error")); |
565 | 0 | } |
566 | 0 | } |
567 | | |
568 | 201 | if (!nbns_tree) |
569 | 0 | return; |
570 | | |
571 | 201 | if (flag & F_RESPONSE) { |
572 | 34 | if (!is_wack) { |
573 | 14 | proto_tree_add_bitmask(nbns_tree, tvb, offset, hf_nbns_flags, ett_nbns_flags, resp_flags, ENC_BIG_ENDIAN); |
574 | 20 | } else { |
575 | 20 | proto_tree_add_bitmask(nbns_tree, tvb, offset, hf_nbns_flags, ett_nbns_flags, resp_wack_flags, ENC_BIG_ENDIAN); |
576 | 20 | } |
577 | 167 | } else { |
578 | 167 | proto_tree_add_bitmask(nbns_tree, tvb, offset, hf_nbns_flags, ett_nbns_flags, req_flags, ENC_BIG_ENDIAN); |
579 | 167 | } |
580 | 201 | } |
581 | | |
582 | | static void |
583 | | nbns_add_nb_flags(proto_tree *rr_tree, tvbuff_t *tvb, int offset) |
584 | 216 | { |
585 | 216 | proto_item *tf; |
586 | 216 | uint16_t flag; |
587 | 216 | static int * const flags[] = { |
588 | 216 | &hf_nbns_nb_flags_group, |
589 | 216 | &hf_nbns_nb_flags_ont, |
590 | 216 | NULL |
591 | 216 | }; |
592 | | |
593 | 216 | tf = proto_tree_add_bitmask(rr_tree, tvb, offset, hf_nbns_nb_flags, ett_nbns_nb_flags, flags, ENC_BIG_ENDIAN); |
594 | | |
595 | 216 | flag = tvb_get_ntohs(tvb, offset); |
596 | 216 | proto_item_append_text(tf, " (%s, %s)", |
597 | 216 | val_to_str_const(flag & NB_FLAGS_ONT, nb_flags_ont_vals, "Unknown"), |
598 | 216 | (flag & NB_FLAGS_G) ? "group" : "unique"); |
599 | 216 | } |
600 | | |
601 | | static void |
602 | | nbns_add_name_flags(proto_tree *rr_tree, tvbuff_t *tvb, int offset) |
603 | 472 | { |
604 | 472 | static int * const flags[] = { |
605 | 472 | &hf_nbns_name_flags_group, |
606 | 472 | &hf_nbns_name_flags_ont, |
607 | 472 | &hf_nbns_name_flags_drg, |
608 | 472 | &hf_nbns_name_flags_cnf, |
609 | 472 | &hf_nbns_name_flags_act, |
610 | 472 | &hf_nbns_name_flags_prm, |
611 | 472 | NULL |
612 | 472 | }; |
613 | | |
614 | 472 | proto_tree_add_bitmask(rr_tree, tvb, offset, hf_nbns_name_flags, ett_nbns_name_flags, flags, ENC_BIG_ENDIAN); |
615 | 472 | } |
616 | | |
617 | | static int |
618 | | dissect_nbns_answer(tvbuff_t *tvb, packet_info *pinfo, int offset, int nbns_data_offset, |
619 | | column_info *cinfo, proto_tree *nbns_tree, int opcode) |
620 | 169 | { |
621 | 169 | int len; |
622 | 169 | char *name; |
623 | 169 | int name_len; |
624 | 169 | int name_type; |
625 | 169 | int type; |
626 | 169 | int dns_class; |
627 | 169 | const char *class_name; |
628 | 169 | const char *type_name; |
629 | 169 | int cur_offset; |
630 | 169 | unsigned ttl; |
631 | 169 | uint16_t data_len; |
632 | 169 | proto_tree *rr_tree = NULL; |
633 | 169 | char *name_str; |
634 | 169 | unsigned num_names; |
635 | 169 | uint8_t *nbname; |
636 | | |
637 | 169 | cur_offset = offset; |
638 | | |
639 | 169 | name = (char *)wmem_alloc(pinfo->pool, MAX_NAME_LEN); |
640 | 169 | name_str = (char *)wmem_alloc(pinfo->pool, MAX_NAME_LEN); |
641 | 169 | nbname = (uint8_t *)wmem_alloc(pinfo->pool, 16+4+1); /* 4 for [<last char>] */ |
642 | | |
643 | 169 | name_len = MAX_NAME_LEN; |
644 | 169 | len = get_nbns_name_type_class(tvb, pinfo->pool, offset, nbns_data_offset, name, |
645 | 169 | &name_len, &name_type, &type, &dns_class); |
646 | 169 | cur_offset += len; |
647 | | |
648 | 169 | type_name = val_to_str_const(type, nb_type_name_vals, "Unknown"); |
649 | 169 | class_name = val_to_str_const(dns_class, dns_classes, "Unknown"); |
650 | | |
651 | 169 | ttl = tvb_get_ntohl(tvb, cur_offset); |
652 | 169 | cur_offset += 4; |
653 | | |
654 | 169 | data_len = tvb_get_ntohs(tvb, cur_offset); |
655 | 169 | cur_offset += 2; |
656 | | |
657 | | /* XXX: This code should be simplified */ |
658 | 169 | switch (type) { |
659 | 12 | case T_NB: /* "NB" record */ |
660 | 12 | if (cinfo != NULL) { |
661 | 0 | if (opcode != OPCODE_WACK) { |
662 | 0 | col_append_fstr(cinfo, COL_INFO, " %s %s", |
663 | 0 | type_name, |
664 | 0 | tvb_ip_to_str(pinfo->pool, tvb, cur_offset+2)); |
665 | 0 | } |
666 | 0 | } |
667 | | |
668 | 12 | if (nbns_tree) { |
669 | 12 | rr_tree = proto_tree_add_subtree_format(nbns_tree, tvb, offset, |
670 | 12 | (cur_offset - offset) + data_len, |
671 | 12 | ett_nbns_rr, NULL, "%s: type %s, class %s", |
672 | 12 | name, type_name, class_name); |
673 | 12 | (void) g_strlcat(name, " (", MAX_NAME_LEN); |
674 | 12 | (void) g_strlcat(name, netbios_name_type_descr(name_type), MAX_NAME_LEN); |
675 | 12 | (void) g_strlcat(name, ")", MAX_NAME_LEN); |
676 | 12 | add_rr_to_tree(rr_tree, pinfo, tvb, offset, name, |
677 | 12 | name_len, type, dns_class, ttl, data_len); |
678 | 12 | } |
679 | 337 | while (data_len > 0) { |
680 | 326 | if (opcode == OPCODE_WACK) { |
681 | | /* WACK response. This doesn't contain the |
682 | | * same type of RR data as other T_NB |
683 | | * responses. */ |
684 | 109 | if (data_len < 2) { |
685 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
686 | 0 | break; |
687 | 0 | } |
688 | 109 | nbns_add_nbns_flags(cinfo, rr_tree, tvb, cur_offset, 1); |
689 | 109 | cur_offset += 2; |
690 | 109 | data_len -= 2; |
691 | 217 | } else { |
692 | 217 | if (data_len < 2) { |
693 | 1 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
694 | 1 | break; |
695 | 1 | } |
696 | 216 | nbns_add_nb_flags(rr_tree, tvb, cur_offset); |
697 | 216 | cur_offset += 2; |
698 | 216 | data_len -= 2; |
699 | | |
700 | 216 | if (data_len < 4) { |
701 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
702 | 0 | break; |
703 | 0 | } |
704 | 216 | proto_tree_add_item(rr_tree, hf_nbns_addr, tvb, cur_offset, 4, ENC_BIG_ENDIAN); |
705 | 216 | cur_offset += 4; |
706 | 216 | data_len -= 4; |
707 | 216 | } |
708 | 326 | } |
709 | 12 | break; |
710 | | |
711 | 38 | case T_NBSTAT: /* "NBSTAT" record */ |
712 | 38 | if (cinfo != NULL) |
713 | 0 | col_append_fstr(cinfo, COL_INFO, " %s", type_name); |
714 | | |
715 | 38 | if (nbns_tree) { |
716 | 38 | rr_tree = proto_tree_add_subtree_format(nbns_tree, tvb, offset, |
717 | 38 | (cur_offset - offset) + data_len, |
718 | 38 | ett_nbns_rr, NULL, "%s: type %s, class %s", |
719 | 38 | name, type_name, class_name); |
720 | 38 | add_rr_to_tree(rr_tree, pinfo, tvb, offset, name, |
721 | 38 | name_len, type, dns_class, ttl, data_len); |
722 | 38 | } |
723 | | |
724 | 38 | if (data_len < 1) { |
725 | 1 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
726 | 1 | break; |
727 | 1 | } |
728 | | |
729 | 37 | num_names = tvb_get_uint8(tvb, cur_offset); |
730 | 37 | proto_tree_add_item(rr_tree, hf_nbns_number_of_names, tvb, cur_offset, 1, ENC_BIG_ENDIAN); |
731 | 37 | cur_offset += 1; |
732 | | |
733 | 530 | while (num_names != 0) { |
734 | 500 | if (data_len < NETBIOS_NAME_LEN) { |
735 | 6 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
736 | 6 | goto out; |
737 | 6 | } |
738 | 494 | if (rr_tree) { |
739 | 494 | tvb_memcpy(tvb, nbname, cur_offset, |
740 | 494 | NETBIOS_NAME_LEN); |
741 | 494 | name_type = process_netbios_name(nbname, |
742 | 494 | name_str, name_len); |
743 | 494 | proto_tree_add_string_format_value(rr_tree, hf_nbns_netbios_name, tvb, cur_offset, |
744 | 494 | NETBIOS_NAME_LEN, name_str, "%s<%02x> (%s)", |
745 | 494 | name_str, name_type, |
746 | 494 | netbios_name_type_descr(name_type)); |
747 | 494 | } |
748 | 494 | cur_offset += NETBIOS_NAME_LEN; |
749 | 494 | data_len -= NETBIOS_NAME_LEN; |
750 | | |
751 | 494 | if (data_len < 2) { |
752 | 1 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
753 | 1 | goto out; |
754 | 1 | } |
755 | 493 | if (rr_tree) { |
756 | 472 | nbns_add_name_flags(rr_tree, tvb, cur_offset); |
757 | 472 | } |
758 | 493 | cur_offset += 2; |
759 | 493 | data_len -= 2; |
760 | | |
761 | 493 | num_names--; |
762 | 493 | } |
763 | | |
764 | 30 | if (data_len < 6) { |
765 | 1 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
766 | 1 | break; |
767 | 1 | } |
768 | | |
769 | 29 | proto_tree_add_item(rr_tree, hf_nbns_unit_id, tvb, cur_offset, 6, ENC_NA); |
770 | 29 | cur_offset += 6; |
771 | 29 | data_len -= 6; |
772 | | |
773 | 29 | if (data_len < 1) { |
774 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
775 | 0 | break; |
776 | 0 | } |
777 | | |
778 | 29 | proto_tree_add_item(rr_tree, hf_nbns_jumpers, tvb, cur_offset, 1, ENC_BIG_ENDIAN); |
779 | 29 | cur_offset += 1; |
780 | 29 | data_len -= 1; |
781 | | |
782 | 29 | if (data_len < 1) { |
783 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
784 | 0 | break; |
785 | 0 | } |
786 | | |
787 | 29 | proto_tree_add_item(rr_tree, hf_nbns_test_result, tvb, cur_offset, 1, ENC_BIG_ENDIAN); |
788 | 29 | cur_offset += 1; |
789 | 29 | data_len -= 1; |
790 | | |
791 | 29 | if (data_len < 2) { |
792 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
793 | 0 | break; |
794 | 0 | } |
795 | | |
796 | 29 | proto_tree_add_item(rr_tree, hf_nbns_version_number, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
797 | 29 | cur_offset += 2; |
798 | 29 | data_len -= 2; |
799 | | |
800 | 29 | if (data_len < 2) { |
801 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
802 | 0 | break; |
803 | 0 | } |
804 | | |
805 | 29 | proto_tree_add_item(rr_tree, hf_nbns_period_of_statistics, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
806 | 29 | cur_offset += 2; |
807 | 29 | data_len -= 2; |
808 | | |
809 | 29 | if (data_len < 2) { |
810 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
811 | 0 | break; |
812 | 0 | } |
813 | | |
814 | 29 | proto_tree_add_item(rr_tree, hf_nbns_num_crcs, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
815 | 29 | cur_offset += 2; |
816 | 29 | data_len -= 2; |
817 | | |
818 | 29 | if (data_len < 2) { |
819 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
820 | 0 | break; |
821 | 0 | } |
822 | | |
823 | 29 | proto_tree_add_item(rr_tree, hf_nbns_num_alignment_errors, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
824 | 29 | cur_offset += 2; |
825 | 29 | data_len -= 2; |
826 | | |
827 | 29 | if (data_len < 2) { |
828 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
829 | 0 | break; |
830 | 0 | } |
831 | | |
832 | 29 | proto_tree_add_item(rr_tree, hf_nbns_num_collisions, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
833 | 29 | cur_offset += 2; |
834 | 29 | data_len -= 2; |
835 | | |
836 | 29 | if (data_len < 2) { |
837 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
838 | 0 | break; |
839 | 0 | } |
840 | | |
841 | 29 | proto_tree_add_item(rr_tree, hf_nbns_num_send_aborts, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
842 | 29 | cur_offset += 2; |
843 | 29 | data_len -= 2; |
844 | | |
845 | 29 | if (data_len < 4) { |
846 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
847 | 0 | break; |
848 | 0 | } |
849 | | |
850 | 29 | proto_tree_add_item(rr_tree, hf_nbns_num_good_sends, tvb, cur_offset, 4, ENC_BIG_ENDIAN); |
851 | 29 | cur_offset += 4; |
852 | 29 | data_len -= 4; |
853 | | |
854 | 29 | if (data_len < 4) { |
855 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
856 | 0 | break; |
857 | 0 | } |
858 | | |
859 | 29 | proto_tree_add_item(rr_tree, hf_nbns_num_good_receives, tvb, cur_offset, 4, ENC_BIG_ENDIAN); |
860 | 29 | cur_offset += 4; |
861 | 29 | data_len -= 4; |
862 | | |
863 | 29 | if (data_len < 2) { |
864 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
865 | 0 | break; |
866 | 0 | } |
867 | | |
868 | 29 | proto_tree_add_item(rr_tree, hf_nbns_num_retransmits, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
869 | 29 | cur_offset += 2; |
870 | 29 | data_len -= 2; |
871 | | |
872 | 29 | if (data_len < 2) { |
873 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
874 | 0 | break; |
875 | 0 | } |
876 | | |
877 | 29 | proto_tree_add_item(rr_tree, hf_nbns_num_no_resource_conditions, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
878 | 29 | cur_offset += 2; |
879 | 29 | data_len -= 2; |
880 | | |
881 | 29 | if (data_len < 2) { |
882 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
883 | 0 | break; |
884 | 0 | } |
885 | | |
886 | 29 | proto_tree_add_item(rr_tree, hf_nbns_num_command_blocks, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
887 | 29 | cur_offset += 2; |
888 | 29 | data_len -= 2; |
889 | | |
890 | 29 | if (data_len < 2) { |
891 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
892 | 0 | break; |
893 | 0 | } |
894 | | |
895 | 29 | proto_tree_add_item(rr_tree, hf_nbns_num_pending_sessions, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
896 | 29 | cur_offset += 2; |
897 | 29 | data_len -= 2; |
898 | | |
899 | 29 | if (data_len < 2) { |
900 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
901 | 0 | break; |
902 | 0 | } |
903 | | |
904 | 29 | proto_tree_add_item(rr_tree, hf_nbns_max_num_pending_sessions, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
905 | 29 | cur_offset += 2; |
906 | 29 | data_len -= 2; |
907 | | |
908 | 29 | if (data_len < 2) { |
909 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
910 | 0 | break; |
911 | 0 | } |
912 | | |
913 | 29 | proto_tree_add_item(rr_tree, hf_nbns_max_total_sessions_possible, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
914 | 29 | cur_offset += 2; |
915 | 29 | data_len -= 2; |
916 | | |
917 | 29 | if (data_len < 2) { |
918 | 0 | proto_tree_add_expert(rr_tree, pinfo, &ei_nbns_incomplete_entry, tvb, cur_offset, data_len); |
919 | 0 | break; |
920 | 0 | } |
921 | | |
922 | 29 | proto_tree_add_item(rr_tree, hf_nbns_session_data_packet_size, tvb, cur_offset, 2, ENC_BIG_ENDIAN); |
923 | 29 | cur_offset += 2; |
924 | | /*data_len -= 2;*/ |
925 | 29 | out: |
926 | 9 | break; |
927 | | |
928 | 100 | default: |
929 | 100 | if (cinfo != NULL) |
930 | 0 | col_append_fstr(cinfo, COL_INFO, " %s", type_name); |
931 | | |
932 | 100 | if (nbns_tree) { |
933 | 100 | rr_tree = proto_tree_add_subtree_format(nbns_tree, tvb, offset, |
934 | 100 | (cur_offset - offset) + data_len, |
935 | 100 | ett_nbns_rr, NULL, "%s: type %s, class %s", |
936 | 100 | name, type_name, class_name); |
937 | 100 | add_rr_to_tree(rr_tree, pinfo, tvb, offset, name, |
938 | 100 | name_len, type, dns_class, ttl, data_len); |
939 | 100 | proto_tree_add_item(rr_tree, hf_nbns_data, tvb, cur_offset, data_len, ENC_NA); |
940 | 100 | } |
941 | 100 | cur_offset += data_len; |
942 | 100 | break; |
943 | 169 | } |
944 | | |
945 | 101 | return cur_offset - offset; |
946 | 169 | } |
947 | | |
948 | | static int |
949 | | dissect_query_records(tvbuff_t *tvb, packet_info* pinfo, int cur_off, int nbns_data_offset, |
950 | | int count, proto_tree *nbns_tree, bool add_column_data) |
951 | 21 | { |
952 | 21 | int start_off, add_off; |
953 | 21 | proto_tree *qatree; |
954 | 21 | proto_item *ti; |
955 | | |
956 | 21 | start_off = cur_off; |
957 | 21 | qatree = proto_tree_add_subtree(nbns_tree, tvb, start_off, -1, ett_nbns_qry, &ti, "Queries"); |
958 | | |
959 | 136 | while (count-- > 0) { |
960 | 115 | add_off = dissect_nbns_query(tvb, pinfo, cur_off, nbns_data_offset, qatree, add_column_data); |
961 | 115 | cur_off += add_off; |
962 | 115 | } |
963 | | |
964 | 21 | proto_item_set_len(ti, cur_off - start_off); |
965 | | |
966 | 21 | return cur_off - start_off; |
967 | 21 | } |
968 | | |
969 | | static int |
970 | | dissect_answer_records(tvbuff_t *tvb, packet_info *pinfo, int cur_off, int nbns_data_offset, |
971 | | int count, column_info *cinfo, proto_tree *nbns_tree, |
972 | | int opcode, const char *name) |
973 | 72 | { |
974 | 72 | int start_off, add_off; |
975 | 72 | proto_tree *qatree; |
976 | 72 | proto_item *ti; |
977 | | |
978 | 72 | start_off = cur_off; |
979 | 72 | qatree = proto_tree_add_subtree(nbns_tree, tvb, start_off, -1, ett_nbns_ans, &ti, name); |
980 | | |
981 | 241 | while (count-- > 0) { |
982 | 169 | add_off = dissect_nbns_answer(tvb, pinfo, cur_off, nbns_data_offset, |
983 | 169 | cinfo, qatree, opcode); |
984 | 169 | cur_off += add_off; |
985 | 169 | } |
986 | | |
987 | 72 | proto_item_set_len(ti, cur_off - start_off); |
988 | 72 | return cur_off - start_off; |
989 | 72 | } |
990 | | |
991 | | static int |
992 | | dissect_nbns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
993 | 92 | { |
994 | 92 | int offset = 0; |
995 | 92 | int nbns_data_offset; |
996 | 92 | proto_tree *nbns_tree = NULL; |
997 | 92 | proto_item *ti; |
998 | 92 | uint32_t id, flags, opcode, quest, ans, auth, add; |
999 | 92 | int cur_off; |
1000 | | |
1001 | 92 | nbns_data_offset = offset; |
1002 | | |
1003 | 92 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBNS"); |
1004 | 92 | col_clear(pinfo->cinfo, COL_INFO); |
1005 | | |
1006 | | /* To do: check for runts, errs, etc. */ |
1007 | 92 | id = tvb_get_ntohs(tvb, offset + NBNS_ID); |
1008 | 92 | flags = tvb_get_ntohs(tvb, offset + NBNS_FLAGS); |
1009 | 92 | opcode = (uint16_t) ((flags & F_OPCODE) >> OPCODE_SHIFT); |
1010 | | |
1011 | 92 | col_add_fstr(pinfo->cinfo, COL_INFO, "%s%s", |
1012 | 92 | val_to_str(pinfo->pool, opcode, opcode_vals, "Unknown operation (%u)"), |
1013 | 92 | (flags & F_RESPONSE) ? " response" : ""); |
1014 | | |
1015 | 92 | ti = proto_tree_add_item(tree, proto_nbns, tvb, offset, -1, ENC_NA); |
1016 | 92 | nbns_tree = proto_item_add_subtree(ti, ett_nbns); |
1017 | | |
1018 | 92 | proto_tree_add_uint(nbns_tree, hf_nbns_transaction_id, tvb, |
1019 | 92 | offset + NBNS_ID, 2, id); |
1020 | | |
1021 | 92 | nbns_add_nbns_flags(pinfo->cinfo, nbns_tree, tvb, offset + NBNS_FLAGS, 0); |
1022 | | |
1023 | 92 | proto_tree_add_item_ret_uint(nbns_tree, hf_nbns_count_questions, tvb, |
1024 | 92 | offset + NBNS_QUEST, 2, ENC_BIG_ENDIAN, &quest); |
1025 | 92 | proto_tree_add_item_ret_uint(nbns_tree, hf_nbns_count_answers, tvb, |
1026 | 92 | offset + NBNS_ANS, 2, ENC_BIG_ENDIAN, &ans); |
1027 | 92 | proto_tree_add_item_ret_uint(nbns_tree, hf_nbns_count_auth_rr, tvb, |
1028 | 92 | offset + NBNS_AUTH, 2, ENC_BIG_ENDIAN, &auth); |
1029 | 92 | proto_tree_add_item_ret_uint(nbns_tree, hf_nbns_count_add_rr, tvb, |
1030 | 92 | offset + NBNS_ADD, 2, ENC_BIG_ENDIAN, &add); |
1031 | | |
1032 | 92 | cur_off = offset + NBNS_HDRLEN; |
1033 | | |
1034 | 92 | if (quest > 0) { |
1035 | | /* If this is a response, don't add information about the |
1036 | | queries to the summary, just add information about the |
1037 | | answers. */ |
1038 | 21 | cur_off += dissect_query_records(tvb, pinfo, cur_off, |
1039 | 21 | nbns_data_offset, quest, |
1040 | 21 | nbns_tree, !(flags & F_RESPONSE)); |
1041 | 21 | } |
1042 | | |
1043 | 92 | if (ans > 0) { |
1044 | | /* If this is a request, don't add information about the |
1045 | | answers to the summary, just add information about the |
1046 | | queries. */ |
1047 | 31 | cur_off += dissect_answer_records(tvb, pinfo, cur_off, |
1048 | 31 | nbns_data_offset, ans, |
1049 | 31 | ((flags & F_RESPONSE) ? pinfo->cinfo : NULL), nbns_tree, |
1050 | 31 | opcode, "Answers"); |
1051 | 31 | } |
1052 | | |
1053 | | /* Don't add information about the authoritative name |
1054 | | servers, or the additional records, to the summary. */ |
1055 | 92 | if (auth > 0) |
1056 | 39 | cur_off += dissect_answer_records(tvb, pinfo, cur_off, |
1057 | 39 | nbns_data_offset, |
1058 | 39 | auth, NULL, nbns_tree, opcode, |
1059 | 39 | "Authoritative nameservers"); |
1060 | | |
1061 | 92 | if (add > 0) |
1062 | 2 | /*cur_off += */dissect_answer_records(tvb, pinfo, cur_off, |
1063 | 2 | nbns_data_offset, |
1064 | 2 | add, NULL, nbns_tree, opcode, |
1065 | 2 | "Additional records"); |
1066 | | |
1067 | 92 | return tvb_captured_length(tvb); |
1068 | 92 | } |
1069 | | |
1070 | | static heur_dissector_list_t netbios_heur_subdissector_list; |
1071 | | |
1072 | | static void |
1073 | | dissect_netbios_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) |
1074 | 122 | { |
1075 | 122 | heur_dtbl_entry_t *hdtbl_entry; |
1076 | | |
1077 | | /* |
1078 | | * Try the heuristic dissectors for NetBIOS; if none of them |
1079 | | * accept the packet, dissect it as data. |
1080 | | */ |
1081 | 122 | if (!dissector_try_heuristic(netbios_heur_subdissector_list, |
1082 | 122 | tvb, pinfo, tree, &hdtbl_entry, NULL)) |
1083 | 57 | call_data_dissector(tvb, pinfo, tree); |
1084 | 122 | } |
1085 | | |
1086 | | /* |
1087 | | * NBDS message types. |
1088 | | */ |
1089 | 0 | #define NBDS_DIRECT_UNIQUE 0x10 |
1090 | 0 | #define NBDS_DIRECT_GROUP 0x11 |
1091 | 70 | #define NBDS_BROADCAST 0x12 |
1092 | 0 | #define NBDS_ERROR 0x13 |
1093 | 1 | #define NBDS_QUERY_REQUEST 0x14 |
1094 | 2 | #define NBDS_POS_QUERY_RESPONSE 0x15 |
1095 | 2 | #define NBDS_NEG_QUERY_RESPONSE 0x16 |
1096 | | |
1097 | | static const value_string nbds_msgtype_vals[] = { |
1098 | | { NBDS_DIRECT_UNIQUE, "Direct_unique datagram" }, |
1099 | | { NBDS_DIRECT_GROUP, "Direct_group datagram" }, |
1100 | | { NBDS_BROADCAST, "Broadcast datagram" }, |
1101 | | { NBDS_ERROR, "Datagram error" }, |
1102 | | { NBDS_QUERY_REQUEST, "Datagram query request" }, |
1103 | | { NBDS_POS_QUERY_RESPONSE, "Datagram positive query response" }, |
1104 | | { NBDS_NEG_QUERY_RESPONSE, "Datagram negative query response" }, |
1105 | | { 0, NULL } |
1106 | | }; |
1107 | | |
1108 | | static const value_string node_type_vals[] = { |
1109 | | { 0, "B node" }, |
1110 | | { 1, "P node" }, |
1111 | | { 2, "M node" }, |
1112 | | { 3, "NBDD" }, |
1113 | | { 0, NULL } |
1114 | | }; |
1115 | | |
1116 | | static const value_string nbds_error_codes[] = { |
1117 | | { 0x82, "Destination name not present" }, |
1118 | | { 0x83, "Invalid source name format" }, |
1119 | | { 0x84, "Invalid destination name format" }, |
1120 | | { 0x00, NULL } |
1121 | | }; |
1122 | | |
1123 | | static int |
1124 | | dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
1125 | 75 | { |
1126 | 75 | int offset = 0; |
1127 | 75 | proto_tree *nbdgm_tree; |
1128 | 75 | proto_item *ti; |
1129 | 75 | tvbuff_t *next_tvb; |
1130 | 75 | uint32_t msg_type; |
1131 | | |
1132 | 75 | char *name; |
1133 | 75 | int name_type; |
1134 | 75 | int len; |
1135 | | |
1136 | 75 | static int * const flags[] = { |
1137 | 75 | &hf_nbdgm_fragment, |
1138 | 75 | &hf_nbdgm_first, |
1139 | 75 | &hf_nbdgm_node_type, |
1140 | 75 | NULL |
1141 | 75 | }; |
1142 | | |
1143 | 75 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBDS"); |
1144 | 75 | col_clear(pinfo->cinfo, COL_INFO); |
1145 | | |
1146 | 75 | ti = proto_tree_add_item(tree, proto_nbdgm, tvb, offset, -1, ENC_NA); |
1147 | 75 | nbdgm_tree = proto_item_add_subtree(ti, ett_nbdgm); |
1148 | | |
1149 | 75 | proto_tree_add_item_ret_uint(nbdgm_tree, hf_nbdgm_type, tvb, |
1150 | 75 | offset, 1, ENC_NA, &msg_type); |
1151 | | |
1152 | 75 | col_add_str(pinfo->cinfo, COL_INFO, |
1153 | 75 | val_to_str(pinfo->pool, msg_type, nbds_msgtype_vals, |
1154 | 75 | "Unknown message type (0x%02X)")); |
1155 | | |
1156 | 75 | proto_tree_add_bitmask(nbdgm_tree, tvb, offset+1, hf_nbdgm_flags, ett_nbdgm_flags, flags, ENC_BIG_ENDIAN); |
1157 | | |
1158 | 75 | proto_tree_add_item(nbdgm_tree, hf_nbdgm_datagram_id, tvb, offset+2, 2, ENC_BIG_ENDIAN); |
1159 | | |
1160 | 75 | proto_tree_add_item(nbdgm_tree, hf_nbdgm_src_ip, tvb, offset+4, 4, ENC_BIG_ENDIAN); |
1161 | | |
1162 | 75 | proto_tree_add_item(nbdgm_tree, hf_nbdgm_src_port, tvb, offset+8, 2, ENC_BIG_ENDIAN); |
1163 | | |
1164 | 75 | offset += 10; |
1165 | | |
1166 | 75 | switch (msg_type) { |
1167 | | |
1168 | 0 | case NBDS_DIRECT_UNIQUE: |
1169 | 0 | case NBDS_DIRECT_GROUP: |
1170 | 70 | case NBDS_BROADCAST: |
1171 | 70 | proto_tree_add_item(nbdgm_tree, hf_nbdgm_datagram_length, |
1172 | 70 | tvb, offset, 2, ENC_BIG_ENDIAN); |
1173 | 70 | offset += 2; |
1174 | | |
1175 | 70 | proto_tree_add_item(nbdgm_tree, hf_nbdgm_packet_offset, |
1176 | 70 | tvb, offset, 2, ENC_BIG_ENDIAN); |
1177 | 70 | offset += 2; |
1178 | | |
1179 | 70 | name = (char *)wmem_alloc(pinfo->pool, MAX_NAME_LEN); |
1180 | | |
1181 | | /* Source name */ |
1182 | 70 | len = get_nbns_name(tvb, pinfo->pool, offset, offset, name, MAX_NAME_LEN, &name_type); |
1183 | | |
1184 | 70 | add_name_and_type(nbdgm_tree, tvb, offset, len, hf_nbdgm_source_name, name, name_type); |
1185 | 70 | offset += len; |
1186 | | |
1187 | | /* Destination name */ |
1188 | 70 | len = get_nbns_name(tvb, pinfo->pool, offset, offset, name, MAX_NAME_LEN, &name_type); |
1189 | | |
1190 | 70 | add_name_and_type(nbdgm_tree, tvb, offset, len, hf_nbdgm_destination_name, name, name_type); |
1191 | 70 | offset += len; |
1192 | | |
1193 | | /* |
1194 | | * Here we can pass the packet off to the next protocol. |
1195 | | * Set the length of our top-level tree item to include |
1196 | | * only our stuff. |
1197 | | * |
1198 | | * XXX - take the datagram length into account, including |
1199 | | * doing datagram reassembly? |
1200 | | */ |
1201 | 70 | proto_item_set_len(ti, offset); |
1202 | 70 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
1203 | 70 | dissect_netbios_payload(next_tvb, pinfo, tree); |
1204 | 70 | break; |
1205 | | |
1206 | 0 | case NBDS_ERROR: |
1207 | 0 | proto_tree_add_item(nbdgm_tree, hf_nbdgm_error_code, tvb, offset, |
1208 | 0 | 1, ENC_BIG_ENDIAN); |
1209 | 0 | offset += 1; |
1210 | 0 | proto_item_set_len(ti, offset); |
1211 | 0 | break; |
1212 | | |
1213 | 1 | case NBDS_QUERY_REQUEST: |
1214 | 2 | case NBDS_POS_QUERY_RESPONSE: |
1215 | 2 | case NBDS_NEG_QUERY_RESPONSE: |
1216 | 2 | name = (char *)wmem_alloc(pinfo->pool, MAX_NAME_LEN); |
1217 | | |
1218 | | /* Destination name */ |
1219 | 2 | len = get_nbns_name(tvb, pinfo->pool, offset, offset, name, MAX_NAME_LEN, &name_type); |
1220 | | |
1221 | 2 | add_name_and_type(nbdgm_tree, tvb, offset, len, |
1222 | 2 | hf_nbdgm_destination_name, name, name_type); |
1223 | 2 | offset += len; |
1224 | 2 | proto_item_set_len(ti, offset); |
1225 | 2 | break; |
1226 | 75 | } |
1227 | 18 | return tvb_captured_length(tvb); |
1228 | 75 | } |
1229 | | |
1230 | | /* |
1231 | | * NetBIOS Session Service message types (RFC 1002). |
1232 | | */ |
1233 | 87 | #define SESSION_MESSAGE 0x00 |
1234 | 1 | #define SESSION_REQUEST 0x81 |
1235 | 0 | #define POSITIVE_SESSION_RESPONSE 0x82 |
1236 | 0 | #define NEGATIVE_SESSION_RESPONSE 0x83 |
1237 | 0 | #define RETARGET_SESSION_RESPONSE 0x84 |
1238 | 0 | #define SESSION_KEEP_ALIVE 0x85 |
1239 | | |
1240 | | static const value_string message_types[] = { |
1241 | | { SESSION_MESSAGE, "Session message" }, |
1242 | | { SESSION_REQUEST, "Session request" }, |
1243 | | { POSITIVE_SESSION_RESPONSE, "Positive session response" }, |
1244 | | { NEGATIVE_SESSION_RESPONSE, "Negative session response" }, |
1245 | | { RETARGET_SESSION_RESPONSE, "Retarget session response" }, |
1246 | | { SESSION_KEEP_ALIVE, "Session keep-alive" }, |
1247 | | { 0x0, NULL } |
1248 | | }; |
1249 | | |
1250 | | /* |
1251 | | * NetBIOS Session Service flags. |
1252 | | */ |
1253 | 165 | #define NBSS_FLAGS_E 0x1 |
1254 | | |
1255 | | static const value_string nbss_error_codes[] = { |
1256 | | { 0x80, "Not listening on called name" }, |
1257 | | { 0x81, "Not listening for calling name" }, |
1258 | | { 0x82, "Called name not present" }, |
1259 | | { 0x83, "Called name present, but insufficient resources" }, |
1260 | | { 0x8F, "Unspecified error" }, |
1261 | | { 0x0, NULL } |
1262 | | }; |
1263 | | |
1264 | | /* |
1265 | | * Dissect a single NBSS packet (there may be more than one in a given |
1266 | | * TCP segment). |
1267 | | * |
1268 | | * [ Hmmm, in my experience, I have never seen more than one NBSS in a |
1269 | | * single segment, since they mostly contain SMBs which are essentially |
1270 | | * a request response type protocol (RJS). ] |
1271 | | * |
1272 | | * [ However, under heavy load with many requests multiplexed on one |
1273 | | * session it is not unusual to see multiple requests in one TCP |
1274 | | * segment. Unfortunately, in this case a single session message is |
1275 | | * frequently split over multiple segments, which frustrates decoding |
1276 | | * (MMM). ] |
1277 | | */ |
1278 | | static void |
1279 | | dissect_nbss_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
1280 | | int is_cifs) |
1281 | 62 | { |
1282 | 62 | int offset = 0; |
1283 | 62 | proto_tree *nbss_tree = NULL; |
1284 | 62 | proto_item *ti = NULL; |
1285 | 62 | uint8_t msg_type; |
1286 | 62 | uint8_t flags; |
1287 | 62 | uint32_t length; |
1288 | 62 | int len; |
1289 | 62 | char *name; |
1290 | 62 | int name_type; |
1291 | 62 | uint8_t error_code; |
1292 | 62 | tvbuff_t *next_tvb; |
1293 | 62 | const char *saved_proto; |
1294 | 62 | static int * const nbss_flags[] = { |
1295 | 62 | &hf_nbss_flags_e, |
1296 | 62 | NULL |
1297 | 62 | }; |
1298 | | |
1299 | 62 | name = (char *)wmem_alloc(pinfo->pool, MAX_NAME_LEN); |
1300 | | |
1301 | 62 | msg_type = tvb_get_uint8(tvb, offset); |
1302 | | |
1303 | 62 | ti = proto_tree_add_item(tree, proto_nbss, tvb, offset, -1, ENC_NA); |
1304 | 62 | nbss_tree = proto_item_add_subtree(ti, ett_nbss); |
1305 | | |
1306 | 62 | proto_tree_add_item(nbss_tree, hf_nbss_type, tvb, offset, 1, ENC_BIG_ENDIAN); |
1307 | | |
1308 | 62 | offset += 1; |
1309 | | |
1310 | 62 | if (is_cifs) { |
1311 | 0 | proto_tree_add_item(nbss_tree, hf_nbss_cifs_length, tvb, offset, 3, ENC_BIG_ENDIAN); |
1312 | 0 | offset += 3; |
1313 | 62 | } else { |
1314 | 62 | flags = tvb_get_uint8(tvb, offset); |
1315 | 62 | proto_tree_add_bitmask(nbss_tree, tvb, offset, hf_nbss_flags, ett_nbss_flags, nbss_flags, ENC_BIG_ENDIAN); |
1316 | | |
1317 | 62 | length = tvb_get_ntohs(tvb, offset + 1); |
1318 | 62 | if (flags & NBSS_FLAGS_E) |
1319 | 5 | length += 0x10000; |
1320 | 62 | proto_tree_add_uint(nbss_tree, hf_nbss_length, tvb, offset, 3, length); |
1321 | | |
1322 | 62 | offset += 3; |
1323 | 62 | } |
1324 | | |
1325 | 62 | switch (msg_type) { |
1326 | | |
1327 | 1 | case SESSION_REQUEST: |
1328 | 1 | len = get_nbns_name(tvb, pinfo->pool, offset, offset, name, MAX_NAME_LEN, &name_type); |
1329 | 1 | if (tree) |
1330 | 1 | add_name_and_type(nbss_tree, tvb, offset, len, |
1331 | 1 | hf_nbss_called_name, name, name_type); |
1332 | 1 | offset += len; |
1333 | | |
1334 | 1 | col_append_fstr(pinfo->cinfo, COL_INFO, ", to %s ", name); |
1335 | | |
1336 | 1 | len = get_nbns_name(tvb, pinfo->pool, offset, offset, name, MAX_NAME_LEN, &name_type); |
1337 | | |
1338 | 1 | if (tree) |
1339 | 0 | add_name_and_type(nbss_tree, tvb, offset, len, |
1340 | 0 | hf_nbss_calling_name, name, name_type); |
1341 | | |
1342 | 1 | col_append_fstr(pinfo->cinfo, COL_INFO, "from %s", name); |
1343 | | |
1344 | 1 | break; |
1345 | | |
1346 | 0 | case NEGATIVE_SESSION_RESPONSE: |
1347 | 0 | error_code = tvb_get_uint8(tvb, offset); |
1348 | 0 | proto_tree_add_uint(nbss_tree, hf_nbss_error_code, tvb, offset, 1, |
1349 | 0 | error_code); |
1350 | |
|
1351 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", |
1352 | 0 | val_to_str(pinfo->pool, error_code, nbss_error_codes, "Unknown (%x)")); |
1353 | |
|
1354 | 0 | break; |
1355 | | |
1356 | 0 | case RETARGET_SESSION_RESPONSE: |
1357 | 0 | proto_tree_add_item(nbss_tree, hf_nbss_retarget_ip_address, |
1358 | 0 | tvb, offset, 4, ENC_BIG_ENDIAN); |
1359 | |
|
1360 | 0 | offset += 4; |
1361 | |
|
1362 | 0 | proto_tree_add_item(nbss_tree, hf_nbss_retarget_port, |
1363 | 0 | tvb, offset, 2, ENC_BIG_ENDIAN); |
1364 | |
|
1365 | 0 | break; |
1366 | | |
1367 | 52 | case SESSION_MESSAGE: |
1368 | | /* |
1369 | | * Here we can pass the message off to the next protocol. |
1370 | | * Set the length of our top-level tree item to include |
1371 | | * only our stuff. |
1372 | | */ |
1373 | 52 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
1374 | | |
1375 | | /* |
1376 | | * Dissect the message. |
1377 | | * |
1378 | | * If it gets an error that means there's no point in |
1379 | | * dissecting any more PDUs, rethrow the exception in |
1380 | | * question. |
1381 | | * |
1382 | | * If it gets any other error, report it and continue, as that |
1383 | | * means that PDU got an error, but that doesn't mean we should |
1384 | | * stop dissecting PDUs within this frame or chunk of reassembled |
1385 | | * data. |
1386 | | */ |
1387 | 52 | saved_proto = pinfo->current_proto; |
1388 | 52 | TRY { |
1389 | 52 | dissect_netbios_payload(next_tvb, pinfo, tree); |
1390 | 52 | } |
1391 | 52 | CATCH_NONFATAL_ERRORS { |
1392 | 1 | show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); |
1393 | 1 | pinfo->current_proto = saved_proto; |
1394 | 1 | } |
1395 | 52 | ENDTRY; |
1396 | 52 | break; |
1397 | | |
1398 | 62 | } |
1399 | 62 | } |
1400 | | |
1401 | | static int |
1402 | | dissect_continuation_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) |
1403 | 3 | { |
1404 | 3 | proto_tree *nbss_tree; |
1405 | 3 | proto_item *ti; |
1406 | | |
1407 | | /* |
1408 | | * It looks like a continuation. |
1409 | | */ |
1410 | 3 | col_set_str(pinfo->cinfo, COL_INFO, "NBSS Continuation Message"); |
1411 | | |
1412 | 3 | if (tree) { |
1413 | 3 | ti = proto_tree_add_item(tree, proto_nbss, tvb, 0, -1, ENC_NA); |
1414 | 3 | nbss_tree = proto_item_add_subtree(ti, ett_nbss); |
1415 | 3 | proto_tree_add_item(nbss_tree, hf_nbss_continuation_data, tvb, 0, -1, ENC_NA); |
1416 | 3 | } |
1417 | | |
1418 | 3 | return tvb_captured_length(tvb); |
1419 | 3 | } |
1420 | | |
1421 | | static int |
1422 | | dissect_nbss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) |
1423 | 14 | { |
1424 | 14 | struct tcpinfo *tcpinfo; |
1425 | 14 | int offset = 0; |
1426 | 14 | unsigned length_remaining; |
1427 | 14 | unsigned plen; |
1428 | 14 | int max_data; |
1429 | 14 | uint8_t msg_type; |
1430 | 14 | uint8_t flags; |
1431 | 14 | uint32_t length; |
1432 | 14 | bool is_cifs; |
1433 | 14 | tvbuff_t *next_tvb; |
1434 | | |
1435 | | /* Reject the packet if data is NULL */ |
1436 | 14 | if (data == NULL) |
1437 | 0 | return 0; |
1438 | 14 | tcpinfo = (struct tcpinfo *)data; |
1439 | | |
1440 | 14 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBSS"); |
1441 | 14 | col_clear(pinfo->cinfo, COL_INFO); |
1442 | | |
1443 | 14 | max_data = tvb_captured_length(tvb); |
1444 | | |
1445 | 14 | msg_type = tvb_get_uint8(tvb, offset); |
1446 | | |
1447 | 14 | if (pinfo->match_uint == TCP_PORT_CIFS) { |
1448 | | /* |
1449 | | * Windows 2000 CIFS clients can dispense completely |
1450 | | * with the NETBIOS encapsulation and directly use CIFS |
1451 | | * over TCP. As would be expected, the framing is |
1452 | | * identical, except that the length is 24 bits instead |
1453 | | * of 17. The only message types used are |
1454 | | * SESSION_MESSAGE and SESSION_KEEP_ALIVE. |
1455 | | */ |
1456 | 1 | is_cifs = true; |
1457 | 13 | } else { |
1458 | 13 | is_cifs = false; |
1459 | 13 | } |
1460 | | |
1461 | | /* |
1462 | | * This might be a continuation of an earlier message. |
1463 | | * (Yes, that might be true even if we're doing TCP reassembly, |
1464 | | * as the first TCP segment in the capture might start in the |
1465 | | * middle of an NBNS message.) |
1466 | | */ |
1467 | | |
1468 | | /* |
1469 | | * If this isn't reassembled data, check to see whether it |
1470 | | * looks like a continuation of a message. |
1471 | | * (If it is reassembled data, it shouldn't be a continuation, |
1472 | | * as reassembly should've gathered the continuations together |
1473 | | * into a message.) |
1474 | | * XXX: Unless it was reassembled because we didn't have enough |
1475 | | * data for a NBSS header, it had a first byte that looked like a |
1476 | | * message type, but it turned out not to be a message but continuation |
1477 | | * data after all. Perhaps we should check even reassembled data, |
1478 | | * at least if it's the first message in the conversation. |
1479 | | */ |
1480 | 14 | if (!tcpinfo->is_reassembled) { |
1481 | 14 | if (max_data < 4) { |
1482 | | /* |
1483 | | * Not enough data for an NBSS header. It could be a message |
1484 | | * split into a very small payload, or a continuation of a message. |
1485 | | */ |
1486 | 1 | if (try_val_to_str(msg_type, message_types)) { |
1487 | | /* |
1488 | | * The first byte looks like a valid message type. |
1489 | | * Can we do reassembly? |
1490 | | */ |
1491 | 0 | if (nbss_desegment && pinfo->can_desegment) { |
1492 | | /* |
1493 | | * Yes. Tell the TCP dissector where the data for this message |
1494 | | * starts in the data it handed us and that we need "some more |
1495 | | * data." Don't tell it exactly how many bytes we need because |
1496 | | * if/when we ask for even more (after the header) that will |
1497 | | * break reassembly. |
1498 | | */ |
1499 | 0 | pinfo->desegment_offset = offset; |
1500 | 0 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; |
1501 | 0 | return tvb_captured_length(tvb); |
1502 | 0 | } |
1503 | 0 | } |
1504 | | /* |
1505 | | * Either we can't do reassembly, or this doesn't look |
1506 | | * like a valid message type. Mark it as continuation. |
1507 | | */ |
1508 | 1 | return dissect_continuation_packet(tvb, pinfo, tree); |
1509 | 1 | } |
1510 | | |
1511 | | /* |
1512 | | * The largest size in for non-SMB NBSS traffic is |
1513 | | * 17 bits (0x1FFFF). |
1514 | | * |
1515 | | * The SMB1 unix extensions and the SMB2 multi credit |
1516 | | * feature allow more than 17 bits (0x1FFFF), they allow |
1517 | | * 24 bits (0xFFFFFF). |
1518 | | * |
1519 | | * So if it is a SESSION_MESSAGE and SMB1 or SMB2 |
1520 | | * mark it as is_cifs. |
1521 | | */ |
1522 | 13 | if (tvb_captured_length_remaining(tvb, offset) >= 8 |
1523 | 11 | && tvb_get_uint8(tvb,offset+0) == SESSION_MESSAGE |
1524 | 10 | && tvb_get_uint8(tvb,offset+5) == 'S' |
1525 | 1 | && tvb_get_uint8(tvb,offset+6) == 'M' |
1526 | 0 | && tvb_get_uint8(tvb,offset+7) == 'B') { |
1527 | 0 | is_cifs = true; |
1528 | 13 | } else { |
1529 | 13 | is_cifs = false; |
1530 | 13 | } |
1531 | | |
1532 | | /* |
1533 | | * We have enough data for an NBSS header. |
1534 | | * Get the flags and length of the message, |
1535 | | * and see if they're sane. |
1536 | | */ |
1537 | 13 | if (is_cifs) { |
1538 | 0 | flags = 0; |
1539 | 0 | length = tvb_get_ntoh24(tvb, offset + 1); |
1540 | 13 | } else { |
1541 | 13 | flags = tvb_get_uint8(tvb, offset + 1); |
1542 | 13 | length = tvb_get_ntohs(tvb, offset + 2); |
1543 | 13 | if (flags & NBSS_FLAGS_E) |
1544 | 2 | length += 0x10000; |
1545 | 13 | } |
1546 | 13 | if ((flags & (~NBSS_FLAGS_E)) != 0) { |
1547 | | /* |
1548 | | * A bogus flag was set; assume it's a continuation. |
1549 | | */ |
1550 | 2 | return dissect_continuation_packet(tvb, pinfo, tree); |
1551 | 2 | } |
1552 | | |
1553 | 11 | switch (msg_type) { |
1554 | | |
1555 | 11 | case SESSION_MESSAGE: |
1556 | | /* |
1557 | | * This is variable-length. |
1558 | | * All we know is that it shouldn't be zero. |
1559 | | * (XXX - can we get zero-length messages? |
1560 | | * Not with SMB, but perhaps other NetBIOS-based |
1561 | | * protocols have them.) |
1562 | | */ |
1563 | 11 | if (length == 0) |
1564 | 0 | return dissect_continuation_packet(tvb, pinfo, tree); |
1565 | | |
1566 | 11 | break; |
1567 | | |
1568 | 11 | case SESSION_REQUEST: |
1569 | | /* |
1570 | | * This is variable-length. |
1571 | | * The names are DNS-encoded 32-byte values; |
1572 | | * we need at least 2 bytes (one for each name; |
1573 | | * actually, we should have more for the first |
1574 | | * name, as there's no name preceding it so |
1575 | | * there should be no compression), and we |
1576 | | * shouldn't have more than 128 bytes (actually, |
1577 | | * we shouldn't have that many). |
1578 | | * |
1579 | | * XXX - actually, Mac OS X 10.1 (yes, that's |
1580 | | * redundant, but that's what Apple calls it, |
1581 | | * not Mac OS X.1) puts names longer than 16 |
1582 | | * characters into session request messages, |
1583 | | * so we can have more than 32 bytes of |
1584 | | * name value, so we can have more than 128 |
1585 | | * bytes of data. |
1586 | | */ |
1587 | 0 | if (length < 2 || length > 256) |
1588 | 0 | return dissect_continuation_packet(tvb, pinfo, tree); |
1589 | 0 | break; |
1590 | | |
1591 | 0 | case POSITIVE_SESSION_RESPONSE: |
1592 | | /* |
1593 | | * This has no data, so the length must be zero. |
1594 | | */ |
1595 | 0 | if (length != 0) |
1596 | 0 | return dissect_continuation_packet(tvb, pinfo, tree); |
1597 | 0 | break; |
1598 | | |
1599 | 0 | case NEGATIVE_SESSION_RESPONSE: |
1600 | | /* |
1601 | | * This has 1 byte of data. |
1602 | | */ |
1603 | 0 | if (length != 1) |
1604 | 0 | return dissect_continuation_packet(tvb, pinfo, tree); |
1605 | 0 | break; |
1606 | | |
1607 | 0 | case RETARGET_SESSION_RESPONSE: |
1608 | | /* |
1609 | | * This has 6 bytes of data. |
1610 | | */ |
1611 | 0 | if (length != 6) |
1612 | 0 | return dissect_continuation_packet(tvb, pinfo, tree); |
1613 | 0 | break; |
1614 | | |
1615 | 0 | case SESSION_KEEP_ALIVE: |
1616 | | /* |
1617 | | * This has no data, so the length must be zero. |
1618 | | */ |
1619 | 0 | if (length != 0) |
1620 | 0 | return dissect_continuation_packet(tvb, pinfo, tree); |
1621 | 0 | break; |
1622 | | |
1623 | 0 | default: |
1624 | | /* |
1625 | | * Unknown message type; assume it's a continuation. |
1626 | | */ |
1627 | 0 | return dissect_continuation_packet(tvb, pinfo, tree); |
1628 | 11 | } |
1629 | 11 | } |
1630 | | |
1631 | 11 | col_add_str(pinfo->cinfo, COL_INFO, |
1632 | 11 | val_to_str(pinfo->pool, msg_type, message_types, "Unknown (%02x)")); |
1633 | | |
1634 | 73 | while ((length_remaining = tvb_reported_length_remaining(tvb, offset)) > 0) { |
1635 | | /* |
1636 | | * Can we do reassembly? |
1637 | | */ |
1638 | 62 | if (nbss_desegment && pinfo->can_desegment) { |
1639 | | /* |
1640 | | * Yes - is the NBSS header split across segment boundaries? |
1641 | | */ |
1642 | 0 | if (length_remaining < 4) { |
1643 | | /* |
1644 | | * Yes. Tell the TCP dissector where the data for this message |
1645 | | * starts in the data it handed us and that we need "some more |
1646 | | * data." Don't tell it exactly how many bytes we need because |
1647 | | * if/when we ask for even more (after the header) that will |
1648 | | * break reassembly. |
1649 | | */ |
1650 | 0 | pinfo->desegment_offset = offset; |
1651 | 0 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; |
1652 | 0 | return tvb_captured_length(tvb); |
1653 | 0 | } |
1654 | 0 | } |
1655 | | |
1656 | | /* |
1657 | | * Get the length of the NBSS message. |
1658 | | */ |
1659 | 62 | if (is_cifs) { |
1660 | 0 | length = tvb_get_ntoh24(tvb, offset + 1); |
1661 | 62 | } else { |
1662 | 62 | flags = tvb_get_uint8(tvb, offset + 1); |
1663 | 62 | length = tvb_get_ntohs(tvb, offset + 2); |
1664 | 62 | if (flags & NBSS_FLAGS_E) |
1665 | 5 | length += 65536; |
1666 | 62 | } |
1667 | 62 | plen = length + 4; /* Include length of NBSS header */ |
1668 | | |
1669 | | /* give a hint to TCP where the next PDU starts |
1670 | | * so that it can attempt to find it in case it starts |
1671 | | * somewhere in the middle of a segment. |
1672 | | */ |
1673 | 62 | if(!pinfo->fd->visited){ |
1674 | | /* 'Only' SMB is transported on top of this, so make sure |
1675 | | * there is an SMB header there ... |
1676 | | */ |
1677 | 62 | if( (plen>tvb_reported_length_remaining(tvb, offset)) |
1678 | 11 | &&(tvb_captured_length_remaining(tvb, offset) >= 8) |
1679 | 8 | &&(tvb_get_uint8(tvb,offset+5) == 'S') |
1680 | 0 | &&(tvb_get_uint8(tvb,offset+6) == 'M') |
1681 | 0 | &&(tvb_get_uint8(tvb,offset+7) == 'B') ){ |
1682 | 0 | pinfo->want_pdu_tracking = 2; |
1683 | 0 | pinfo->bytes_until_next_pdu = (length+4)-tvb_reported_length_remaining(tvb, offset); |
1684 | 0 | } |
1685 | 62 | } |
1686 | | |
1687 | | /* |
1688 | | * Can we do reassembly? |
1689 | | */ |
1690 | 62 | if (nbss_desegment && pinfo->can_desegment) { |
1691 | | /* |
1692 | | * Yes - is the NBSS message split across segment boundaries? |
1693 | | */ |
1694 | 0 | if (length_remaining < plen) { |
1695 | | /* |
1696 | | * Yes. Tell the TCP dissector where the data for this message |
1697 | | * starts in the data it handed us, and how many more bytes we |
1698 | | * need, and return. |
1699 | | */ |
1700 | 0 | pinfo->desegment_offset = offset; |
1701 | 0 | pinfo->desegment_len = plen - length_remaining; |
1702 | 0 | return tvb_captured_length(tvb); |
1703 | 0 | } |
1704 | 0 | } |
1705 | | |
1706 | | /* |
1707 | | * Construct a tvbuff containing the amount of the payload we have |
1708 | | * available. Make its reported length the amount of data in the PDU. |
1709 | | */ |
1710 | 62 | next_tvb = tvb_new_subset_length(tvb, offset, plen); |
1711 | | |
1712 | 62 | dissect_nbss_packet(next_tvb, pinfo, tree, is_cifs); |
1713 | | |
1714 | 62 | offset += plen; |
1715 | 62 | } |
1716 | | |
1717 | 11 | return tvb_captured_length(tvb); |
1718 | 11 | } |
1719 | | |
1720 | | void |
1721 | | proto_register_nbt(void) |
1722 | 15 | { |
1723 | | |
1724 | 15 | static hf_register_info hf_nbns[] = { |
1725 | 15 | { &hf_nbns_flags, |
1726 | 15 | { "Flags", "nbns.flags", |
1727 | 15 | FT_UINT16, BASE_HEX, NULL, 0x0, |
1728 | 15 | NULL, HFILL }}, |
1729 | 15 | { &hf_nbns_flags_response, |
1730 | 15 | { "Response", "nbns.flags.response", |
1731 | 15 | FT_BOOLEAN, 16, TFS(&tfs_flags_response), F_RESPONSE, |
1732 | 15 | "Is the message a response?", HFILL }}, |
1733 | 15 | { &hf_nbns_flags_opcode, |
1734 | 15 | { "Opcode", "nbns.flags.opcode", |
1735 | 15 | FT_UINT16, BASE_DEC, VALS(opcode_vals), F_OPCODE, |
1736 | 15 | "Operation code", HFILL }}, |
1737 | 15 | { &hf_nbns_flags_authoritative, |
1738 | 15 | { "Authoritative", "nbns.flags.authoritative", |
1739 | 15 | FT_BOOLEAN, 16, TFS(&tfs_flags_authoritative), F_AUTHORITATIVE, |
1740 | 15 | "Is the server is an authority for the domain?", HFILL }}, |
1741 | 15 | { &hf_nbns_flags_truncated, |
1742 | 15 | { "Truncated", "nbns.flags.truncated", |
1743 | 15 | FT_BOOLEAN, 16, TFS(&tfs_flags_truncated), F_TRUNCATED, |
1744 | 15 | "Is the message truncated?", HFILL }}, |
1745 | 15 | { &hf_nbns_flags_recdesired, |
1746 | 15 | { "Recursion desired", "nbns.flags.recdesired", |
1747 | 15 | FT_BOOLEAN, 16, TFS(&tfs_flags_recdesired), F_RECDESIRED, |
1748 | 15 | "Do query recursively?", HFILL }}, |
1749 | 15 | { &hf_nbns_flags_recavail, |
1750 | 15 | { "Recursion available", "nbns.flags.recavail", |
1751 | 15 | FT_BOOLEAN, 16, TFS(&tfs_flags_recavail), F_RECAVAIL, |
1752 | 15 | "Can the server do recursive queries?", HFILL }}, |
1753 | 15 | { &hf_nbns_flags_broadcast, |
1754 | 15 | { "Broadcast", "nbns.flags.broadcast", |
1755 | 15 | FT_BOOLEAN, 16, TFS(&tfs_flags_broadcast), F_BROADCAST, |
1756 | 15 | "Is this a broadcast packet?", HFILL }}, |
1757 | 15 | { &hf_nbns_flags_rcode, |
1758 | 15 | { "Reply code", "nbns.flags.rcode", |
1759 | 15 | FT_UINT16, BASE_DEC, VALS(rcode_vals), F_RCODE, |
1760 | 15 | NULL, HFILL }}, |
1761 | 15 | { &hf_nbns_transaction_id, |
1762 | 15 | { "Transaction ID", "nbns.id", |
1763 | 15 | FT_UINT16, BASE_HEX, NULL, 0x0, |
1764 | 15 | "Identification of transaction", HFILL }}, |
1765 | 15 | { &hf_nbns_count_questions, |
1766 | 15 | { "Questions", "nbns.count.queries", |
1767 | 15 | FT_UINT16, BASE_DEC, NULL, 0x0, |
1768 | 15 | "Number of queries in packet", HFILL }}, |
1769 | 15 | { &hf_nbns_count_answers, |
1770 | 15 | { "Answer RRs", "nbns.count.answers", |
1771 | 15 | FT_UINT16, BASE_DEC, NULL, 0x0, |
1772 | 15 | "Number of answers in packet", HFILL }}, |
1773 | 15 | { &hf_nbns_count_auth_rr, |
1774 | 15 | { "Authority RRs", "nbns.count.auth_rr", |
1775 | 15 | FT_UINT16, BASE_DEC, NULL, 0x0, |
1776 | 15 | "Number of authoritative records in packet", HFILL }}, |
1777 | 15 | { &hf_nbns_count_add_rr, |
1778 | 15 | { "Additional RRs", "nbns.count.add_rr", |
1779 | 15 | FT_UINT16, BASE_DEC, NULL, 0x0, |
1780 | 15 | "Number of additional records in packet", HFILL }}, |
1781 | 15 | { &hf_nbns_name_flags, |
1782 | 15 | { "Name flags", "nbns.name_flags", |
1783 | 15 | FT_UINT16, BASE_HEX, NULL, 0x0, |
1784 | 15 | NULL, HFILL }}, |
1785 | 15 | { &hf_nbns_name_flags_group, |
1786 | 15 | { "Name type", "nbns.name_flags.group", |
1787 | 15 | FT_BOOLEAN, 16, TFS(&tfs_group_unique_name), NAME_FLAGS_G, |
1788 | 15 | NULL, HFILL }}, |
1789 | 15 | { &hf_nbns_name_flags_ont, |
1790 | 15 | { "ONT", "nbns.name_flags.ont", |
1791 | 15 | FT_UINT16, BASE_DEC, VALS(name_flags_ont_vals), NAME_FLAGS_ONT, |
1792 | 15 | NULL, HFILL }}, |
1793 | 15 | { &hf_nbns_name_flags_drg, |
1794 | 15 | { "Name is being deregistered", "nbns.name_flags.drg", |
1795 | 15 | FT_BOOLEAN, 16, TFS(&tfs_yes_no), NAME_FLAGS_DRG, |
1796 | 15 | NULL, HFILL }}, |
1797 | 15 | { &hf_nbns_name_flags_cnf, |
1798 | 15 | { "Name is in conflict", "nbns.name_flags.cnf", |
1799 | 15 | FT_BOOLEAN, 16, TFS(&tfs_yes_no), NAME_FLAGS_CNF, |
1800 | 15 | NULL, HFILL }}, |
1801 | 15 | { &hf_nbns_name_flags_act, |
1802 | 15 | { "Name is active", "nbns.name_flags.act", |
1803 | 15 | FT_BOOLEAN, 16, TFS(&tfs_yes_no), NAME_FLAGS_ACT, |
1804 | 15 | NULL, HFILL }}, |
1805 | 15 | { &hf_nbns_name_flags_prm, |
1806 | 15 | { "Permanent node name", "nbns.name_flags.prm", |
1807 | 15 | FT_BOOLEAN, 16, TFS(&tfs_yes_no), NAME_FLAGS_PRM, |
1808 | 15 | NULL, HFILL }}, |
1809 | 15 | { &hf_nbns_nb_flags, |
1810 | 15 | { "Name flags", "nbns.nb_flags", |
1811 | 15 | FT_UINT16, BASE_HEX, NULL, 0x0, |
1812 | 15 | NULL, HFILL }}, |
1813 | 15 | { &hf_nbns_nb_flags_group, |
1814 | 15 | { "Name type", "nbns.nb_flags.group", |
1815 | 15 | FT_BOOLEAN, 16, TFS(&tfs_group_unique_name), NB_FLAGS_G, |
1816 | 15 | NULL, HFILL }}, |
1817 | 15 | { &hf_nbns_nb_flags_ont, |
1818 | 15 | { "ONT", "nbns.nb_flags.ont", |
1819 | 15 | FT_UINT16, BASE_DEC, VALS(nb_flags_ont_vals), NB_FLAGS_ONT, |
1820 | 15 | NULL, HFILL }}, |
1821 | 15 | { &hf_nbns_type, |
1822 | 15 | { "Type", "nbns.type", |
1823 | 15 | FT_UINT16, BASE_DEC, VALS(nb_type_name_vals), 0x0, |
1824 | 15 | NULL, HFILL }}, |
1825 | 15 | { &hf_nbns_class, |
1826 | 15 | { "Class", "nbns.class", |
1827 | 15 | FT_UINT16, BASE_DEC, VALS(dns_classes), 0x0, |
1828 | 15 | NULL, HFILL }}, |
1829 | 15 | { &hf_nbns_name, |
1830 | 15 | { "Name", "nbns.name", |
1831 | 15 | FT_STRING, BASE_NONE, NULL, 0x0, |
1832 | 15 | NULL, HFILL }}, |
1833 | | |
1834 | | /* Generated from convert_proto_tree_add_text.pl */ |
1835 | 15 | { &hf_nbns_addr, { "Addr", "nbns.addr", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
1836 | 15 | { &hf_nbns_number_of_names, { "Number of names", "nbns.number_of_names", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1837 | 15 | { &hf_nbns_unit_id, { "Unit ID", "nbns.unit_id", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
1838 | 15 | { &hf_nbns_jumpers, { "Jumpers", "nbns.jumpers", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
1839 | 15 | { &hf_nbns_test_result, { "Test result", "nbns.test_result", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
1840 | 15 | { &hf_nbns_version_number, { "Version number", "nbns.version_number", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
1841 | 15 | { &hf_nbns_period_of_statistics, { "Period of statistics", "nbns.period_of_statistics", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
1842 | 15 | { &hf_nbns_num_crcs, { "Number of CRCs", "nbns.num_crcs", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1843 | 15 | { &hf_nbns_num_alignment_errors, { "Number of alignment errors", "nbns.num_alignment_errors", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1844 | 15 | { &hf_nbns_num_collisions, { "Number of collisions", "nbns.num_collisions", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1845 | 15 | { &hf_nbns_num_send_aborts, { "Number of send aborts", "nbns.num_send_aborts", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1846 | 15 | { &hf_nbns_num_good_sends, { "Number of good sends", "nbns.num_good_sends", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1847 | 15 | { &hf_nbns_num_good_receives, { "Number of good receives", "nbns.num_good_receives", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1848 | 15 | { &hf_nbns_num_retransmits, { "Number of retransmits", "nbns.numretransmits", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1849 | 15 | { &hf_nbns_num_no_resource_conditions, { "Number of no resource conditions", "nbns.num_no_resource_conditions", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1850 | 15 | { &hf_nbns_num_command_blocks, { "Number of command blocks", "nbns.numcommand_blocks", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1851 | 15 | { &hf_nbns_num_pending_sessions, { "Number of pending sessions", "nbns.numpending_sessions", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1852 | 15 | { &hf_nbns_max_num_pending_sessions, { "Max number of pending sessions", "nbns.max_num_pending_sessions", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1853 | 15 | { &hf_nbns_max_total_sessions_possible, { "Max total sessions possible", "nbns.max_total_sessions_possible", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1854 | 15 | { &hf_nbns_session_data_packet_size, { "Session data packet size", "nbns.session_data_packet_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1855 | 15 | { &hf_nbns_data, { "Data", "nbns.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
1856 | 15 | { &hf_nbns_netbios_name, { "Name", "nbns.netbios_name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
1857 | 15 | { &hf_nbns_ttl, { "Time to live", "nbns.ttl", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1858 | 15 | { &hf_nbns_data_length, { "Data length", "nbns.data_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1859 | 15 | }; |
1860 | | |
1861 | 15 | static hf_register_info hf_nbdgm[] = { |
1862 | 15 | { &hf_nbdgm_type, |
1863 | 15 | { "Message Type", "nbdgm.type", |
1864 | 15 | FT_UINT8, BASE_DEC, VALS(nbds_msgtype_vals), 0x0, |
1865 | 15 | "NBDGM message type", HFILL }}, |
1866 | 15 | { &hf_nbdgm_flags, |
1867 | 15 | { "Flags", "nbdgm.flags", |
1868 | 15 | FT_UINT8, BASE_HEX, NULL, 0x0, |
1869 | 15 | NULL, HFILL }}, |
1870 | 15 | { &hf_nbdgm_fragment, |
1871 | 15 | { "More fragments follow", "nbdgm.next", |
1872 | 15 | FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, |
1873 | 15 | "true if more fragments follow", HFILL }}, |
1874 | 15 | { &hf_nbdgm_first, |
1875 | 15 | { "This is first fragment", "nbdgm.first", |
1876 | 15 | FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02, |
1877 | 15 | "true if first fragment", HFILL }}, |
1878 | 15 | { &hf_nbdgm_node_type, |
1879 | 15 | { "Node Type", "nbdgm.node_type", |
1880 | 15 | FT_UINT8, BASE_DEC, VALS(node_type_vals), 0x0C, |
1881 | 15 | NULL, HFILL }}, |
1882 | 15 | { &hf_nbdgm_datagram_id, |
1883 | 15 | { "Datagram ID", "nbdgm.dgram_id", |
1884 | 15 | FT_UINT16, BASE_HEX, NULL, 0x0, |
1885 | 15 | "Datagram identifier", HFILL }}, |
1886 | 15 | { &hf_nbdgm_src_ip, |
1887 | 15 | { "Source IP", "nbdgm.src.ip", |
1888 | 15 | FT_IPv4, BASE_NONE, NULL, 0x0, |
1889 | 15 | "Source IPv4 address", HFILL }}, |
1890 | 15 | { &hf_nbdgm_src_port, |
1891 | 15 | { "Source Port", "nbdgm.src.port", |
1892 | 15 | FT_UINT16, BASE_DEC, NULL, 0x0, |
1893 | 15 | NULL, HFILL }}, |
1894 | 15 | { &hf_nbdgm_datagram_length, |
1895 | 15 | { "Datagram length", "nbdgm.dgram_len", |
1896 | 15 | FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, |
1897 | 15 | NULL, HFILL }}, |
1898 | 15 | { &hf_nbdgm_packet_offset, |
1899 | 15 | { "Packet offset", "nbdgm.pkt_offset", |
1900 | 15 | FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, |
1901 | 15 | NULL, HFILL }}, |
1902 | 15 | { &hf_nbdgm_error_code, |
1903 | 15 | { "Error code", "nbdgm.error_code", |
1904 | 15 | FT_UINT8, BASE_HEX, VALS(nbds_error_codes), 0x0, |
1905 | 15 | NULL, HFILL }}, |
1906 | 15 | { &hf_nbdgm_source_name, |
1907 | 15 | { "Source name", "nbdgm.source_name", |
1908 | 15 | FT_STRING, BASE_NONE, NULL, 0x0, |
1909 | 15 | NULL, HFILL }}, |
1910 | 15 | { &hf_nbdgm_destination_name, |
1911 | 15 | { "Destination name", "nbdgm.destination_name", |
1912 | 15 | FT_STRING, BASE_NONE, NULL, 0x0, |
1913 | 15 | NULL, HFILL }}, |
1914 | 15 | }; |
1915 | | |
1916 | 15 | static hf_register_info hf_nbss[] = { |
1917 | 15 | { &hf_nbss_type, |
1918 | 15 | { "Message Type", "nbss.type", |
1919 | 15 | FT_UINT8, BASE_HEX, VALS(message_types), 0x0, |
1920 | 15 | "NBSS message type", HFILL }}, |
1921 | 15 | { &hf_nbss_flags, |
1922 | 15 | { "Flags", "nbss.flags", |
1923 | 15 | FT_UINT8, BASE_HEX, NULL, 0x0, |
1924 | 15 | "NBSS message flags", HFILL }}, |
1925 | 15 | { &hf_nbss_flags_e, |
1926 | 15 | { "Extend", "nbss.flags.e", |
1927 | 15 | FT_BOOLEAN, 8, TFS(&tfs_nbss_flags_e), NBSS_FLAGS_E, |
1928 | 15 | NULL, HFILL }}, |
1929 | 15 | { &hf_nbss_length, |
1930 | 15 | { "Length", "nbss.length", |
1931 | 15 | FT_UINT24, BASE_DEC, NULL, 0x0, |
1932 | 15 | "Length of trailer (payload) following this field in bytes", HFILL }}, |
1933 | 15 | { &hf_nbss_cifs_length, |
1934 | 15 | { "Length", "nbss.length", |
1935 | 15 | FT_UINT24, BASE_DEC, NULL, 0x0, |
1936 | 15 | "Length trailer (payload) following this field in bytes", HFILL }}, |
1937 | 15 | { &hf_nbss_error_code, |
1938 | 15 | { "Error code", "nbss.error_code", |
1939 | 15 | FT_UINT8, BASE_HEX, VALS(nbss_error_codes), 0x0, |
1940 | 15 | NULL, HFILL }}, |
1941 | 15 | { &hf_nbss_retarget_ip_address, |
1942 | 15 | { "Retarget IP address", "nbss.retarget_ip_address", |
1943 | 15 | FT_IPv4, BASE_NONE, NULL, 0x0, |
1944 | 15 | NULL, HFILL }}, |
1945 | 15 | { &hf_nbss_retarget_port, |
1946 | 15 | { "Retarget port", "nbss.retarget_port", |
1947 | 15 | FT_UINT16, BASE_DEC, NULL, 0x0, |
1948 | 15 | NULL, HFILL }}, |
1949 | 15 | { &hf_nbss_continuation_data, |
1950 | 15 | { "Continuation data", "nbss.continuation_data", |
1951 | 15 | FT_BYTES, BASE_NONE, NULL, 0x0, |
1952 | 15 | NULL, HFILL }}, |
1953 | 15 | { &hf_nbss_called_name, |
1954 | 15 | { "Called name", "nbss.called_name", |
1955 | 15 | FT_STRING, BASE_NONE, NULL, 0x0, |
1956 | 15 | NULL, HFILL }}, |
1957 | 15 | { &hf_nbss_calling_name, |
1958 | 15 | { "Calling name", "nbss.calling_name", |
1959 | 15 | FT_STRING, BASE_NONE, NULL, 0x0, |
1960 | 15 | NULL, HFILL }}, |
1961 | 15 | }; |
1962 | 15 | static int *ett[] = { |
1963 | 15 | &ett_nbns, |
1964 | 15 | &ett_nbns_qd, |
1965 | 15 | &ett_nbns_flags, |
1966 | 15 | &ett_nbns_nb_flags, |
1967 | 15 | &ett_nbns_name_flags, |
1968 | 15 | &ett_nbns_rr, |
1969 | 15 | &ett_nbns_qry, |
1970 | 15 | &ett_nbns_ans, |
1971 | 15 | &ett_nbdgm, |
1972 | 15 | &ett_nbdgm_flags, |
1973 | 15 | &ett_nbss, |
1974 | 15 | &ett_nbss_flags, |
1975 | 15 | }; |
1976 | | |
1977 | 15 | static ei_register_info ei[] = { |
1978 | 15 | { &ei_nbns_incomplete_entry, { "nbns.incomplete_entry", PI_MALFORMED, PI_ERROR, "incomplete entry", EXPFILL }}, |
1979 | 15 | }; |
1980 | | |
1981 | 15 | module_t *nbss_module; |
1982 | 15 | expert_module_t* expert_nbns; |
1983 | | |
1984 | 15 | proto_nbns = proto_register_protocol("NetBIOS Name Service", "NBNS", "nbns"); |
1985 | 15 | nbns_handle = register_dissector("nbns", dissect_nbns, proto_nbns); |
1986 | 15 | proto_register_field_array(proto_nbns, hf_nbns, array_length(hf_nbns)); |
1987 | 15 | expert_nbns = expert_register_protocol(proto_nbns); |
1988 | 15 | expert_register_field_array(expert_nbns, ei, array_length(ei)); |
1989 | | |
1990 | 15 | proto_nbdgm = proto_register_protocol("NetBIOS Datagram Service", |
1991 | 15 | "NBDS", "nbdgm"); |
1992 | 15 | nbdgm_handle = register_dissector("nbds", dissect_nbdgm, proto_nbdgm); |
1993 | 15 | proto_register_field_array(proto_nbdgm, hf_nbdgm, array_length(hf_nbdgm)); |
1994 | | |
1995 | 15 | proto_nbss = proto_register_protocol("NetBIOS Session Service", |
1996 | 15 | "NBSS", "nbss"); |
1997 | 15 | nbss_handle = register_dissector("nbss", dissect_nbss, proto_nbss); |
1998 | 15 | proto_register_field_array(proto_nbss, hf_nbss, array_length(hf_nbss)); |
1999 | | |
2000 | 15 | proto_register_subtree_array(ett, array_length(ett)); |
2001 | | |
2002 | 15 | nbss_module = prefs_register_protocol(proto_nbss, NULL); |
2003 | 15 | prefs_register_bool_preference(nbss_module, "desegment_nbss_commands", |
2004 | 15 | "Reassemble NBSS packets spanning multiple TCP segments", |
2005 | 15 | "Whether the NBSS dissector should reassemble packets spanning multiple TCP segments." |
2006 | 15 | " To use this option, you must also enable" |
2007 | 15 | " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", |
2008 | 15 | &nbss_desegment); |
2009 | 15 | } |
2010 | | |
2011 | | void |
2012 | | proto_reg_handoff_nbt(void) |
2013 | 15 | { |
2014 | 15 | dissector_add_uint_with_preference("udp.port", UDP_PORT_NBNS, nbns_handle); |
2015 | 15 | dissector_add_uint_with_preference("udp.port", UDP_PORT_NBDGM, nbdgm_handle); |
2016 | 15 | dissector_add_uint_range_with_preference("tcp.port", TCP_NBSS_PORT_RANGE, nbss_handle); |
2017 | | |
2018 | 15 | netbios_heur_subdissector_list = find_heur_dissector_list("netbios"); |
2019 | | |
2020 | 15 | dissector_add_string("quic.proto", "smb", nbss_handle); |
2021 | 15 | } |
2022 | | |
2023 | | /* |
2024 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
2025 | | * |
2026 | | * Local variables: |
2027 | | * c-basic-offset: 4 |
2028 | | * tab-width: 8 |
2029 | | * indent-tabs-mode: nil |
2030 | | * End: |
2031 | | * |
2032 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
2033 | | * :indentSize=4:tabSize=8:noTabs=true: |
2034 | | */ |