2 * Routines for NetBIOS-over-TCP packet disassembly (the name dates back
3 * to when it had only NBNS)
4 * Gilbert Ramirez <gram@verdict.uthscsa.edu>
5 * Much stuff added by Guy Harris <guy@netapp.com>
7 * $Id: packet-nbns.c,v 1.30 1999/10/07 09:21:38 guy Exp $
9 * Ethereal - Network traffic analyzer
10 * By Gerald Combs <gerald@zing.org>
11 * Copyright 1998 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
41 #include "packet-dns.h"
42 #include "packet-netbios.h"
45 static int proto_nbns = -1;
46 static int proto_nbdgm = -1;
47 static int proto_nbss = -1;
49 /* Packet structure taken from RFC 1002. See also RFC 1001.
50 * Opcode, flags, and rcode treated as "flags", similarly to DNS,
51 * to make it easier to lift the dissection code from "packet-dns.c". */
53 /* Offsets of fields in the NBNS header. */
61 /* Length of NBNS header. */
62 #define NBNS_HDRLEN 12
65 #define T_NB 32 /* NetBIOS name service RR */
66 #define T_NBSTAT 33 /* NetBIOS node status RR */
68 /* Bit fields in the flags */
69 #define F_RESPONSE (1<<15) /* packet is response */
70 #define F_OPCODE (0xF<<11) /* query opcode */
71 #define F_AUTHORITATIVE (1<<10) /* response is authoritative */
72 #define F_TRUNCATED (1<<9) /* response is truncated */
73 #define F_RECDESIRED (1<<8) /* recursion desired */
74 #define F_RECAVAIL (1<<7) /* recursion available */
75 #define F_BROADCAST (1<<4) /* broadcast/multicast packet */
76 #define F_RCODE (0xF<<0) /* reply code */
79 #define OPCODE_QUERY (0<<11) /* standard query */
80 #define OPCODE_REGISTRATION (5<<11) /* registration */
81 #define OPCODE_RELEASE (6<<11) /* release name */
82 #define OPCODE_WACK (7<<11) /* wait for acknowledgement */
83 #define OPCODE_REFRESH (8<<11) /* refresh registration */
84 #define OPCODE_REFRESHALT (9<<11) /* refresh registration (alternate opcode) */
85 #define OPCODE_MHREGISTRATION (15<<11) /* multi-homed registration */
88 #define RCODE_NOERROR (0<<0)
89 #define RCODE_FMTERROR (1<<0)
90 #define RCODE_SERVFAIL (2<<0)
91 #define RCODE_NAMEERROR (3<<0)
92 #define RCODE_NOTIMPL (4<<0)
93 #define RCODE_REFUSED (5<<0)
94 #define RCODE_ACTIVE (6<<0)
95 #define RCODE_CONFLICT (7<<0)
97 /* Values for the "NB_FLAGS" field of RR data. From RFC 1001 and 1002,
98 * except for NB_FLAGS_ONT_H_NODE, which was discovered by looking at
100 #define NB_FLAGS_ONT (3<<(15-2)) /* bits for node type */
101 #define NB_FLAGS_ONT_B_NODE (0<<(15-2)) /* B-mode node */
102 #define NB_FLAGS_ONT_P_NODE (1<<(15-2)) /* P-mode node */
103 #define NB_FLAGS_ONT_M_NODE (2<<(15-2)) /* M-mode node */
104 #define NB_FLAGS_ONT_H_NODE (3<<(15-2)) /* H-mode node */
106 #define NB_FLAGS_G (1<<(15-0)) /* group name */
108 /* Values for the "NAME_FLAGS" field of a NODE_NAME entry in T_NBSTAT
109 * RR data. From RFC 1001 and 1002, except for NAME_FLAGS_ONT_H_NODE,
110 * which was discovered by looking at packet traces. */
111 #define NAME_FLAGS_PRM (1<<(15-6)) /* name is permanent node name */
113 #define NAME_FLAGS_ACT (1<<(15-5)) /* name is active */
115 #define NAME_FLAGS_CNF (1<<(15-4)) /* name is in conflict */
117 #define NAME_FLAGS_DRG (1<<(15-3)) /* name is being deregistered */
119 #define NAME_FLAGS_ONT (3<<(15-2)) /* bits for node type */
120 #define NAME_FLAGS_ONT_B_NODE (0<<(15-2)) /* B-mode node */
121 #define NAME_FLAGS_ONT_P_NODE (1<<(15-2)) /* P-mode node */
122 #define NAME_FLAGS_ONT_M_NODE (2<<(15-2)) /* M-mode node */
124 #define NAME_FLAGS_G (1<<(15-0)) /* group name */
126 static const value_string opcode_vals[] = {
127 { OPCODE_QUERY, "Name query" },
128 { OPCODE_REGISTRATION, "Registration" },
129 { OPCODE_RELEASE, "Release" },
130 { OPCODE_WACK, "Wait for acknowledgment" },
131 { OPCODE_REFRESH, "Refresh" },
132 { OPCODE_REFRESHALT, "Refresh (alternate opcode)" },
133 { OPCODE_MHREGISTRATION, "Multi-homed registration" },
138 nbns_type_name (int type)
151 get_nbns_name(const u_char *pd, int offset, int nbns_data_offset,
152 char *name_ret, int *name_type_ret)
156 char nbname[NETBIOS_NAME_LEN];
157 char *pname, *pnbname, cname, cnbname;
160 name_len = get_dns_name(pd, offset, nbns_data_offset, name,
163 /* OK, now undo the first-level encoding. */
165 pnbname = &nbname[0];
167 /* Every two characters of the first level-encoded name
168 * turn into one character in the decoded name. */
171 break; /* no more characters */
173 break; /* scope ID follows */
174 if (cname < 'A' || cname > 'Z') {
177 "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
181 cnbname = cname << 4;
185 if (cname == '\0' || cname == '.') {
186 /* No more characters in the name - but we're in
187 * the middle of a pair. Not legal. */
189 "Illegal NetBIOS name (odd number of bytes)");
192 if (cname < 'A' || cname > 'Z') {
195 "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
202 /* Do we have room to store the character? */
203 if (pnbname < &nbname[NETBIOS_NAME_LEN]) {
204 /* Yes - store the character. */
208 /* We bump the pointer even if it's past the end of the
209 name, so we keep track of how long the name is. */
213 /* NetBIOS names are supposed to be exactly 16 bytes long. */
214 if (pnbname - nbname != NETBIOS_NAME_LEN) {
216 sprintf(nbname, "Illegal NetBIOS name (%ld bytes long)",
217 (long)(pnbname - nbname));
221 /* This one is; make its name printable. */
222 name_type = process_netbios_name(nbname, name_ret);
223 name_ret += strlen(name_ret);
224 sprintf(name_ret, "<%02x>", name_type);
227 /* We have a scope ID, starting at "pname"; append that to
228 * the decoded host name. */
229 strcpy(name_ret, pname);
231 if (name_type_ret != NULL)
232 *name_type_ret = name_type;
236 if (name_type_ret != NULL)
238 strcpy (name_ret, nbname);
244 get_nbns_name_type_class(const u_char *pd, int offset, int nbns_data_offset,
245 char *name_ret, int *name_len_ret, int *name_type_ret, int *type_ret,
252 name_len = get_nbns_name(pd, offset, nbns_data_offset, name_ret,
256 if (!BYTES_ARE_IN_FRAME(offset, 2)) {
257 /* We ran past the end of the captured data in the packet. */
260 type = pntohs(&pd[offset]);
263 if (!BYTES_ARE_IN_FRAME(offset, 2)) {
264 /* We ran past the end of the captured data in the packet. */
267 class = pntohs(&pd[offset]);
271 *name_len_ret = name_len;
277 add_name_and_type(proto_tree *tree, int offset, int len, char *tag,
278 char *name, int name_type)
280 if (name_type != -1) {
281 proto_tree_add_text(tree, offset, len, "%s: %s (%s)",
282 tag, name, netbios_name_type_descr(name_type));
284 proto_tree_add_text(tree, offset, len, "%s: %s",
290 dissect_nbns_query(const u_char *pd, int offset, int nbns_data_offset,
291 proto_tree *nbns_tree)
294 char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
302 const u_char *data_start;
306 data_start = dptr = pd + offset;
308 len = get_nbns_name_type_class(pd, offset, nbns_data_offset, name,
309 &name_len, &name_type, &type, &class);
311 /* We ran past the end of the data in the packet. */
316 type_name = nbns_type_name(type);
317 class_name = dns_class_name(class);
319 tq = proto_tree_add_text(nbns_tree, offset, len, "%s: type %s, class %s",
320 name, type_name, class_name);
321 q_tree = proto_item_add_subtree(tq, ETT_NBNS_QD);
323 add_name_and_type(q_tree, offset, name_len, "Name", name, name_type);
326 proto_tree_add_text(q_tree, offset, 2, "Type: %s", type_name);
329 proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
332 return dptr - data_start;
336 nbns_add_nbns_flags(proto_tree *nbns_tree, int offset, u_short flags,
340 proto_tree *field_tree;
342 static const value_string rcode_vals[] = {
343 { RCODE_NOERROR, "No error" },
344 { RCODE_FMTERROR, "Request was invalidly formatted" },
345 { RCODE_SERVFAIL, "Server failure" },
346 { RCODE_NAMEERROR, "Requested name does not exist" },
347 { RCODE_NOTIMPL, "Request is not implemented" },
348 { RCODE_REFUSED, "Request was refused" },
349 { RCODE_ACTIVE, "Name is owned by another node" },
350 { RCODE_CONFLICT, "Name is in conflict" },
354 strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals,
355 "Unknown operation"));
356 if (flags & F_RESPONSE && !is_wack) {
357 strcat(buf, " response");
359 strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
362 tf = proto_tree_add_text(nbns_tree, offset, 2,
363 "Flags: 0x%04x (%s)", flags, buf);
364 field_tree = proto_item_add_subtree(tf, ETT_NBNS_FLAGS);
365 proto_tree_add_text(field_tree, offset, 2, "%s",
366 decode_boolean_bitfield(flags, F_RESPONSE,
367 2*8, "Response", "Query"));
368 proto_tree_add_text(field_tree, offset, 2, "%s",
369 decode_enumerated_bitfield(flags, F_OPCODE,
370 2*8, opcode_vals, "%s"));
371 if (flags & F_RESPONSE) {
372 proto_tree_add_text(field_tree, offset, 2,
374 decode_boolean_bitfield(flags, F_AUTHORITATIVE,
376 "Server is an authority for domain",
377 "Server isn't an authority for domain"));
379 proto_tree_add_text(field_tree, offset, 2, "%s",
380 decode_boolean_bitfield(flags, F_TRUNCATED,
382 "Message is truncated",
383 "Message is not truncated"));
384 proto_tree_add_text(field_tree, offset, 2, "%s",
385 decode_boolean_bitfield(flags, F_RECDESIRED,
387 "Do query recursively",
388 "Don't do query recursively"));
389 if (flags & F_RESPONSE) {
390 proto_tree_add_text(field_tree, offset, 2,
392 decode_boolean_bitfield(flags, F_RECAVAIL,
394 "Server can do recursive queries",
395 "Server can't do recursive queries"));
397 proto_tree_add_text(field_tree, offset, 2, "%s",
398 decode_boolean_bitfield(flags, F_BROADCAST,
401 "Not a broadcast packet"));
402 if (flags & F_RESPONSE && !is_wack) {
403 proto_tree_add_text(field_tree, offset, 2,
405 decode_enumerated_bitfield(flags, F_RCODE,
412 nbns_add_nb_flags(proto_tree *rr_tree, int offset, u_short flags)
415 proto_tree *field_tree;
417 static const value_string nb_flags_ont_vals[] = {
418 { NB_FLAGS_ONT_B_NODE, "B-node" },
419 { NB_FLAGS_ONT_P_NODE, "P-node" },
420 { NB_FLAGS_ONT_M_NODE, "M-node" },
421 { NB_FLAGS_ONT_H_NODE, "H-node" },
425 strcpy(buf, val_to_str(flags & NB_FLAGS_ONT, nb_flags_ont_vals,
428 if (flags & NB_FLAGS_G)
429 strcat(buf, "group");
431 strcat(buf, "unique");
432 tf = proto_tree_add_text(rr_tree, offset, 2, "Flags: 0x%x (%s)", flags,
434 field_tree = proto_item_add_subtree(tf, ETT_NBNS_NB_FLAGS);
435 proto_tree_add_text(field_tree, offset, 2, "%s",
436 decode_boolean_bitfield(flags, NB_FLAGS_G,
440 proto_tree_add_text(field_tree, offset, 2, "%s",
441 decode_enumerated_bitfield(flags, NB_FLAGS_ONT,
442 2*8, nb_flags_ont_vals, "%s"));
446 nbns_add_name_flags(proto_tree *rr_tree, int offset, u_short flags)
449 proto_item *field_tree;
451 static const value_string name_flags_ont_vals[] = {
452 { NAME_FLAGS_ONT_B_NODE, "B-node" },
453 { NAME_FLAGS_ONT_P_NODE, "P-node" },
454 { NAME_FLAGS_ONT_M_NODE, "M-node" },
458 strcpy(buf, val_to_str(flags & NAME_FLAGS_ONT, name_flags_ont_vals,
461 if (flags & NAME_FLAGS_G)
462 strcat(buf, "group");
464 strcat(buf, "unique");
465 if (flags & NAME_FLAGS_DRG)
466 strcat(buf, ", being deregistered");
467 if (flags & NAME_FLAGS_CNF)
468 strcat(buf, ", in conflict");
469 if (flags & NAME_FLAGS_ACT)
470 strcat(buf, ", active");
471 if (flags & NAME_FLAGS_PRM)
472 strcat(buf, ", permanent node name");
473 tf = proto_tree_add_text(rr_tree, offset, 2, "Name flags: 0x%x (%s)",
475 field_tree = proto_item_add_subtree(tf, ETT_NBNS_NAME_FLAGS);
476 proto_tree_add_text(field_tree, offset, 2, "%s",
477 decode_boolean_bitfield(flags, NAME_FLAGS_G,
481 proto_tree_add_text(field_tree, offset, 2, "%s",
482 decode_enumerated_bitfield(flags, NAME_FLAGS_ONT,
483 2*8, name_flags_ont_vals, "%s"));
484 proto_tree_add_text(field_tree, offset, 2, "%s",
485 decode_boolean_bitfield(flags, NAME_FLAGS_DRG,
487 "Name is being deregistered",
488 "Name is not being deregistered"));
489 proto_tree_add_text(field_tree, offset, 2, "%s",
490 decode_boolean_bitfield(flags, NAME_FLAGS_CNF,
492 "Name is in conflict",
493 "Name is not in conflict"));
494 proto_tree_add_text(field_tree, offset, 2, "%s",
495 decode_boolean_bitfield(flags, NAME_FLAGS_ACT,
498 "Name is not active"));
499 proto_tree_add_text(field_tree, offset, 2, "%s",
500 decode_boolean_bitfield(flags, NAME_FLAGS_PRM,
502 "Permanent node name",
503 "Not permanent node name"));
507 dissect_nbns_answer(const u_char *pd, int offset, int nbns_data_offset,
508 proto_tree *nbns_tree, int opcode)
511 char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME + 64];
520 const u_char *data_start;
526 char name_str[(NETBIOS_NAME_LEN - 1)*4 + 1];
528 data_start = dptr = pd + offset;
531 len = get_nbns_name_type_class(pd, offset, nbns_data_offset, name,
532 &name_len, &name_type, &type, &class);
534 /* We ran past the end of the data in the packet. */
540 type_name = nbns_type_name(type);
541 class_name = dns_class_name(class);
543 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
544 /* We ran past the end of the captured data in the packet. */
551 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
552 /* We ran past the end of the captured data in the packet. */
555 data_len = pntohs(dptr);
560 case T_NB: /* "NB" record */
561 trr = proto_tree_add_text(nbns_tree, offset,
562 (dptr - data_start) + data_len,
563 "%s: type %s, class %s",
564 name, type_name, class_name);
566 strcat(name, netbios_name_type_descr(name_type));
568 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
569 name_len, type_name, class_name, ttl, data_len);
570 while (data_len > 0) {
571 if (opcode == OPCODE_WACK) {
572 /* WACK response. This doesn't contain the
573 * same type of RR data as other T_NB
575 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
576 /* We ran past the end of the captured
577 data in the packet. */
581 proto_tree_add_text(rr_tree, cur_offset,
582 data_len, "(incomplete entry)");
585 flags = pntohs(dptr);
587 nbns_add_nbns_flags(rr_tree, cur_offset,
592 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
593 /* We ran past the end of the captured
594 data in the packet. */
598 proto_tree_add_text(rr_tree, cur_offset,
599 data_len, "(incomplete entry)");
602 flags = pntohs(dptr);
604 nbns_add_nb_flags(rr_tree, cur_offset, flags);
608 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
609 /* We ran past the end of the captured
610 data in the packet. */
614 proto_tree_add_text(rr_tree, cur_offset,
615 data_len, "(incomplete entry)");
618 proto_tree_add_text(rr_tree, cur_offset, 4,
620 ip_to_str((guint8 *)dptr));
628 case T_NBSTAT: /* "NBSTAT" record */
631 char nbname[16+4+1]; /* 4 for [<last char>] */
634 trr = proto_tree_add_text(nbns_tree, offset,
635 (dptr - data_start) + data_len,
636 "%s: type %s, class %s",
637 name, type_name, class_name);
638 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
639 name_len, type_name, class_name, ttl, data_len);
640 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
641 /* We ran past the end of the captured
642 data in the packet. */
646 proto_tree_add_text(rr_tree, cur_offset,
647 data_len, "(incomplete entry)");
652 proto_tree_add_text(rr_tree, cur_offset, 2,
653 "Number of names: %u", num_names);
656 while (num_names != 0) {
657 if (!BYTES_ARE_IN_FRAME(cur_offset, NETBIOS_NAME_LEN)) {
658 /* We ran past the end of the captured
659 data in the packet. */
662 if (data_len < NETBIOS_NAME_LEN) {
663 proto_tree_add_text(rr_tree, cur_offset,
664 data_len, "(incomplete entry)");
667 memcpy(nbname, dptr, NETBIOS_NAME_LEN);
668 dptr += NETBIOS_NAME_LEN;
669 name_type = process_netbios_name(nbname,
671 proto_tree_add_text(rr_tree, cur_offset,
672 NETBIOS_NAME_LEN, "Name: %s<%02x> (%s)",
674 netbios_name_type_descr(name_type));
675 cur_offset += NETBIOS_NAME_LEN;
676 data_len -= NETBIOS_NAME_LEN;
678 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
679 /* We ran past the end of the captured
680 data in the packet. */
684 proto_tree_add_text(rr_tree, cur_offset,
685 data_len, "(incomplete entry)");
688 name_flags = pntohs(dptr);
690 nbns_add_name_flags(rr_tree, cur_offset, name_flags);
697 if (!BYTES_ARE_IN_FRAME(cur_offset, 6)) {
698 /* We ran past the end of the captured
699 data in the packet. */
703 proto_tree_add_text(rr_tree, cur_offset,
704 data_len, "(incomplete entry)");
707 proto_tree_add_text(rr_tree, cur_offset, 6,
709 ether_to_str((guint8 *)dptr));
714 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
715 /* We ran past the end of the captured
716 data in the packet. */
720 proto_tree_add_text(rr_tree, cur_offset,
721 data_len, "(incomplete entry)");
724 proto_tree_add_text(rr_tree, cur_offset, 1,
725 "Jumpers: 0x%x", *dptr);
730 if (!BYTES_ARE_IN_FRAME(cur_offset, 1)) {
731 /* We ran past the end of the captured
732 data in the packet. */
736 proto_tree_add_text(rr_tree, cur_offset,
737 data_len, "(incomplete entry)");
740 proto_tree_add_text(rr_tree, cur_offset, 1,
741 "Test result: 0x%x", *dptr);
746 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
747 /* We ran past the end of the captured
748 data in the packet. */
752 proto_tree_add_text(rr_tree, cur_offset,
753 data_len, "(incomplete entry)");
756 proto_tree_add_text(rr_tree, cur_offset, 2,
757 "Version number: 0x%x", pntohs(dptr));
762 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
763 /* We ran past the end of the captured
764 data in the packet. */
768 proto_tree_add_text(rr_tree, cur_offset,
769 data_len, "(incomplete entry)");
772 proto_tree_add_text(rr_tree, cur_offset, 2,
773 "Period of statistics: 0x%x", pntohs(dptr));
778 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
779 /* We ran past the end of the captured
780 data in the packet. */
784 proto_tree_add_text(rr_tree, cur_offset,
785 data_len, "(incomplete entry)");
788 proto_tree_add_text(rr_tree, cur_offset, 2,
789 "Number of CRCs: %u", pntohs(dptr));
794 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
795 /* We ran past the end of the captured
796 data in the packet. */
800 proto_tree_add_text(rr_tree, cur_offset,
801 data_len, "(incomplete entry)");
804 proto_tree_add_text(rr_tree, cur_offset, 2,
805 "Number of alignment errors: %u", pntohs(dptr));
810 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
811 /* We ran past the end of the captured
812 data in the packet. */
816 proto_tree_add_text(rr_tree, cur_offset,
817 data_len, "(incomplete entry)");
820 proto_tree_add_text(rr_tree, cur_offset, 2,
821 "Number of collisions: %u", pntohs(dptr));
826 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
827 /* We ran past the end of the captured
828 data in the packet. */
832 proto_tree_add_text(rr_tree, cur_offset,
833 data_len, "(incomplete entry)");
836 proto_tree_add_text(rr_tree, cur_offset, 2,
837 "Number of send aborts: %u", pntohs(dptr));
842 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
843 /* We ran past the end of the captured
844 data in the packet. */
848 proto_tree_add_text(rr_tree, cur_offset,
849 data_len, "(incomplete entry)");
852 proto_tree_add_text(rr_tree, cur_offset, 4,
853 "Number of good sends: %u", pntohl(dptr));
858 if (!BYTES_ARE_IN_FRAME(cur_offset, 4)) {
859 /* We ran past the end of the captured
860 data in the packet. */
864 proto_tree_add_text(rr_tree, cur_offset,
865 data_len, "(incomplete entry)");
868 proto_tree_add_text(rr_tree, cur_offset, 4,
869 "Number of good receives: %u", pntohl(dptr));
874 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
875 /* We ran past the end of the captured
876 data in the packet. */
880 proto_tree_add_text(rr_tree, cur_offset,
881 data_len, "(incomplete entry)");
884 proto_tree_add_text(rr_tree, cur_offset, 2,
885 "Number of retransmits: %u", pntohs(dptr));
890 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
891 /* We ran past the end of the captured
892 data in the packet. */
896 proto_tree_add_text(rr_tree, cur_offset,
897 data_len, "(incomplete entry)");
900 proto_tree_add_text(rr_tree, cur_offset, 2,
901 "Number of no resource conditions: %u", pntohs(dptr));
906 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
907 /* We ran past the end of the captured
908 data in the packet. */
912 proto_tree_add_text(rr_tree, cur_offset,
913 data_len, "(incomplete entry)");
916 proto_tree_add_text(rr_tree, cur_offset, 2,
917 "Number of command blocks: %u", pntohs(dptr));
922 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
923 /* We ran past the end of the captured
924 data in the packet. */
928 proto_tree_add_text(rr_tree, cur_offset,
929 data_len, "(incomplete entry)");
932 proto_tree_add_text(rr_tree, cur_offset, 2,
933 "Number of pending sessions: %u", pntohs(dptr));
938 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
939 /* We ran past the end of the captured
940 data in the packet. */
944 proto_tree_add_text(rr_tree, cur_offset,
945 data_len, "(incomplete entry)");
948 proto_tree_add_text(rr_tree, cur_offset, 2,
949 "Max number of pending sessions: %u", pntohs(dptr));
953 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
954 /* We ran past the end of the captured
955 data in the packet. */
959 proto_tree_add_text(rr_tree, cur_offset,
960 data_len, "(incomplete entry)");
963 proto_tree_add_text(rr_tree, cur_offset, 2,
964 "Max total sessions possible: %u", pntohs(dptr));
969 if (!BYTES_ARE_IN_FRAME(cur_offset, 2)) {
970 /* We ran past the end of the captured
971 data in the packet. */
975 proto_tree_add_text(rr_tree, cur_offset,
976 data_len, "(incomplete entry)");
979 proto_tree_add_text(rr_tree, cur_offset, 2,
980 "Session data packet size: %u", pntohs(dptr));
989 trr = proto_tree_add_text(nbns_tree, offset,
990 (dptr - data_start) + data_len,
991 "%s: type %s, class %s",
992 name, type_name, class_name);
993 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
994 name_len, type_name, class_name, ttl, data_len);
995 proto_tree_add_text(rr_tree, cur_offset, data_len, "Data");
1000 return dptr - data_start;
1004 dissect_query_records(const u_char *pd, int cur_off, int nbns_data_offset,
1005 int count, proto_tree *nbns_tree)
1007 int start_off, add_off;
1011 start_off = cur_off;
1012 ti = proto_tree_add_text(nbns_tree, start_off, 0, "Queries");
1013 qatree = proto_item_add_subtree(ti, ETT_NBNS_QRY);
1014 while (count-- > 0) {
1015 add_off = dissect_nbns_query(pd, cur_off, nbns_data_offset,
1018 /* We ran past the end of the captured data in the
1024 proto_item_set_len(ti, cur_off - start_off);
1026 return cur_off - start_off;
1032 dissect_answer_records(const u_char *pd, int cur_off, int nbns_data_offset,
1033 int count, proto_tree *nbns_tree, int opcode, char *name)
1035 int start_off, add_off;
1039 start_off = cur_off;
1040 ti = proto_tree_add_text(nbns_tree, start_off, 0, name);
1041 qatree = proto_item_add_subtree(ti, ETT_NBNS_ANS);
1042 while (count-- > 0) {
1043 add_off = dissect_nbns_answer(pd, cur_off, nbns_data_offset,
1046 /* We ran past the end of the captured data in the
1052 proto_item_set_len(ti, cur_off - start_off);
1053 return cur_off - start_off;
1057 dissect_nbns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1059 int nbns_data_offset;
1060 proto_tree *nbns_tree;
1062 guint16 id, flags, quest, ans, auth, add;
1065 nbns_data_offset = offset;
1067 if (check_col(fd, COL_PROTOCOL))
1068 col_add_str(fd, COL_PROTOCOL, "NBNS (UDP)");
1070 if (pi.captured_len < NBNS_HDRLEN) {
1071 col_add_str(fd, COL_INFO, "Short NBNS packet");
1072 dissect_data(pd, offset, fd, tree);
1076 /* To do: check for runts, errs, etc. */
1077 id = pntohs(&pd[offset + NBNS_ID]);
1078 flags = pntohs(&pd[offset + NBNS_FLAGS]);
1079 quest = pntohs(&pd[offset + NBNS_QUEST]);
1080 ans = pntohs(&pd[offset + NBNS_ANS]);
1081 auth = pntohs(&pd[offset + NBNS_AUTH]);
1082 add = pntohs(&pd[offset + NBNS_ADD]);
1084 if (check_col(fd, COL_INFO)) {
1085 col_add_fstr(fd, COL_INFO, "%s%s",
1086 val_to_str(flags & F_OPCODE, opcode_vals,
1087 "Unknown operation (%x)"),
1088 (flags & F_RESPONSE) ? " response" : "");
1092 ti = proto_tree_add_item(tree, proto_nbns, offset, END_OF_FRAME, NULL);
1093 nbns_tree = proto_item_add_subtree(ti, ETT_NBNS);
1095 proto_tree_add_text(nbns_tree, offset + NBNS_ID, 2,
1096 "Transaction ID: 0x%04X", id);
1098 nbns_add_nbns_flags(nbns_tree, offset + NBNS_FLAGS, flags, 0);
1099 proto_tree_add_text(nbns_tree, offset + NBNS_QUEST, 2,
1102 proto_tree_add_text(nbns_tree, offset + NBNS_ANS, 2,
1105 proto_tree_add_text(nbns_tree, offset + NBNS_AUTH, 2,
1106 "Authority RRs: %d",
1108 proto_tree_add_text(nbns_tree, offset + NBNS_ADD, 2,
1109 "Additional RRs: %d",
1112 cur_off = offset + NBNS_HDRLEN;
1115 cur_off += dissect_query_records(pd, cur_off,
1116 nbns_data_offset, quest, nbns_tree);
1119 cur_off += dissect_answer_records(pd, cur_off,
1126 cur_off += dissect_answer_records(pd, cur_off,
1130 "Authoritative nameservers");
1133 cur_off += dissect_answer_records(pd, cur_off,
1137 "Additional records");
1141 /* NetBIOS datagram packet, from RFC 1002, page 32 */
1142 struct nbdgm_header {
1153 /* For packets with data */
1157 /* For error packets */
1162 dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1164 proto_tree *nbdgm_tree = NULL;
1166 struct nbdgm_header header;
1169 int max_data = pi.captured_len - offset;
1173 "Direct_unique datagram",
1174 "Direct_group datagram",
1175 "Broadcast datagram",
1177 "Datagram query request",
1178 "Datagram positive query response",
1179 "Datagram negative query response"
1189 static value_string error_codes[] = {
1190 { 0x82, "Destination name not present" },
1191 { 0x83, "Invalid source name format" },
1192 { 0x84, "Invalid destination name format" },
1196 char *yesno[] = { "No", "Yes" };
1198 char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
1202 header.msg_type = pd[offset];
1204 flags = pd[offset+1];
1205 header.flags.more = flags & 1;
1206 header.flags.first = (flags & 2) >> 1;
1207 header.flags.node_type = (flags & 12) >> 2;
1209 header.dgm_id = pntohs(&pd[offset+2]);
1210 memcpy(&header.src_ip, &pd[offset+4], 4);
1211 header.src_port = pntohs(&pd[offset+8]);
1213 if (header.msg_type == 0x10 ||
1214 header.msg_type == 0x11 || header.msg_type == 0x12) {
1215 header.dgm_length = pntohs(&pd[offset+10]);
1216 header.pkt_offset = pntohs(&pd[offset+12]);
1218 else if (header.msg_type == 0x13) {
1219 header.error_code = pntohs(&pd[offset+10]);
1222 message_index = header.msg_type - 0x0f;
1223 if (message_index < 1 || message_index > 8) {
1227 if (check_col(fd, COL_PROTOCOL))
1228 col_add_str(fd, COL_PROTOCOL, "NBDS (UDP)");
1229 if (check_col(fd, COL_INFO)) {
1230 col_add_fstr(fd, COL_INFO, "%s", message[message_index]);
1234 ti = proto_tree_add_item(tree, proto_nbdgm, offset, header.dgm_length, NULL);
1235 nbdgm_tree = proto_item_add_subtree(ti, ETT_NBDGM);
1237 proto_tree_add_text(nbdgm_tree, offset, 1, "Message Type: %s",
1238 message[message_index]);
1239 proto_tree_add_text(nbdgm_tree, offset+1, 1, "More fragments follow: %s",
1240 yesno[header.flags.more]);
1241 proto_tree_add_text(nbdgm_tree, offset+1, 1, "This is first fragment: %s",
1242 yesno[header.flags.first]);
1243 proto_tree_add_text(nbdgm_tree, offset+1, 1, "Node Type: %s",
1244 node[header.flags.node_type]);
1246 proto_tree_add_text(nbdgm_tree, offset+2, 2, "Datagram ID: 0x%04X",
1248 proto_tree_add_text(nbdgm_tree, offset+4, 4, "Source IP: %s",
1249 ip_to_str((guint8 *)&header.src_ip));
1250 proto_tree_add_text(nbdgm_tree, offset+8, 2, "Source Port: %d",
1257 if (header.msg_type == 0x10 ||
1258 header.msg_type == 0x11 || header.msg_type == 0x12) {
1261 proto_tree_add_text(nbdgm_tree, offset, 2,
1262 "Datagram length: %d bytes", header.dgm_length);
1263 proto_tree_add_text(nbdgm_tree, offset+2, 2,
1264 "Packet offset: %d bytes", header.pkt_offset);
1271 len = get_nbns_name(pd, offset, offset, name, &name_type);
1274 add_name_and_type(nbdgm_tree, offset, len,
1275 "Source name", name, name_type);
1280 /* Destination name */
1281 len = get_nbns_name(pd, offset, offset, name, &name_type);
1284 add_name_and_type(nbdgm_tree, offset, len,
1285 "Destination name", name, name_type);
1290 /* here we can pass the packet off to the next protocol */
1291 dissect_smb(pd, offset, fd, tree, max_data);
1293 else if (header.msg_type == 0x13) {
1295 proto_tree_add_text(nbdgm_tree, offset, 1, "Error code: %s",
1296 val_to_str(header.error_code, error_codes, "Unknown (0x%x)"));
1299 else if (header.msg_type == 0x14 ||
1300 header.msg_type == 0x15 || header.msg_type == 0x16) {
1301 /* Destination name */
1302 len = get_nbns_name(pd, offset, offset, name, &name_type);
1305 add_name_and_type(nbdgm_tree, offset, len,
1306 "Destination name", name, name_type);
1312 * NetBIOS Session Service message types.
1314 #define SESSION_MESSAGE 0x00
1315 #define SESSION_REQUEST 0x81
1316 #define POSITIVE_SESSION_RESPONSE 0x82
1317 #define NEGATIVE_SESSION_RESPONSE 0x83
1318 #define RETARGET_SESSION_RESPONSE 0x84
1319 #define SESSION_KEEP_ALIVE 0x85
1321 static const value_string message_types[] = {
1322 { SESSION_MESSAGE, "Session message" },
1323 { SESSION_REQUEST, "Session request" },
1324 { POSITIVE_SESSION_RESPONSE, "Positive session response" },
1325 { NEGATIVE_SESSION_RESPONSE, "Negative session response" },
1326 { RETARGET_SESSION_RESPONSE, "Retarget session response" },
1327 { SESSION_KEEP_ALIVE, "Session keep-alive" },
1332 * NetBIOS Session Service flags.
1334 #define NBSS_FLAGS_E 0x1
1336 static const value_string error_codes[] = {
1337 { 0x80, "Not listening on called name" },
1338 { 0x81, "Not listening for called name" },
1339 { 0x82, "Called name not present" },
1340 { 0x83, "Called name present, but insufficient resources" },
1341 { 0x8F, "Unspecified error" },
1346 * Dissect a single NBSS packet (there may be more than one in a given TCP
1347 * segment). Hmmm, in my experience, I have never seen more than one NBSS
1348 * in a single segment, since they mostly contain SMBs which are essentially
1349 * a request response type protocol (RJS). Also, a single session message
1350 * may be split over multiple segments.
1353 dissect_nbss_packet(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int max_data)
1355 proto_tree *nbss_tree = NULL;
1357 proto_tree *field_tree;
1363 char name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
1366 msg_type = pd[offset];
1367 flags = pd[offset + 1];
1368 length = pntohs(&pd[offset + 2]);
1369 if (flags & NBSS_FLAGS_E)
1373 ti = proto_tree_add_item(tree, proto_nbss, offset, length + 4, NULL);
1374 nbss_tree = proto_item_add_subtree(ti, ETT_NBSS);
1376 proto_tree_add_text(nbss_tree, offset, 1, "Message Type: %s",
1377 val_to_str(msg_type, message_types, "Unknown (%x)"));
1383 tf = proto_tree_add_text(nbss_tree, offset, 1, "Flags: 0x%04x", flags);
1384 field_tree = proto_item_add_subtree(tf, ETT_NBSS_FLAGS);
1385 proto_tree_add_text(field_tree, offset, 1, "%s",
1386 decode_boolean_bitfield(flags, NBSS_FLAGS_E,
1387 8, "Add 65536 to length", "Add 0 to length"));
1393 proto_tree_add_text(nbss_tree, offset, 2, "Length: %u", length);
1400 case SESSION_REQUEST:
1401 len = get_nbns_name(pd, offset, offset, name, &name_type);
1403 add_name_and_type(nbss_tree, offset, len,
1404 "Called name", name, name_type);
1407 len = get_nbns_name(pd, offset, offset, name, &name_type);
1410 add_name_and_type(nbss_tree, offset, len,
1411 "Calling name", name, name_type);
1415 case NEGATIVE_SESSION_RESPONSE:
1417 proto_tree_add_text(nbss_tree, offset, 1,
1419 val_to_str(pd[offset], error_codes, "Unknown (%x)"));
1422 case RETARGET_SESSION_RESPONSE:
1424 proto_tree_add_text(nbss_tree, offset, 4,
1425 "Retarget IP address: %s",
1426 ip_to_str((guint8 *)&pd[offset]));
1431 proto_tree_add_text(nbss_tree, offset, 2,
1432 "Retarget port: %u", pntohs(&pd[offset]));
1436 case SESSION_MESSAGE:
1438 * Here we can pass the packet off to the next protocol.
1441 dissect_smb(pd, offset, fd, tree, max_data - 4);
1450 dissect_nbss(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1458 msg_type = pd[offset];
1459 flags = pd[offset + 1];
1460 length = pntohs(&pd[offset + 2]);
1461 if (flags & NBSS_FLAGS_E)
1465 * XXX - we should set this based on both "pi.captured_len"
1468 max_data = pi.captured_len - offset;
1470 /* Hmmm, it may be a continuation message ... */
1474 if (((msg_type != SESSION_REQUEST) &&
1475 (msg_type != POSITIVE_SESSION_RESPONSE) &&
1476 (msg_type != NEGATIVE_SESSION_RESPONSE) &&
1477 (msg_type != RETARGET_SESSION_RESPONSE) &&
1478 (msg_type != SESSION_MESSAGE)) ||
1479 ((msg_type == SESSION_MESSAGE) &&
1480 (memcmp(pd + offset + 4, "\377SMB", 4) != 0))) {
1482 if (check_col(fd, COL_PROTOCOL))
1483 col_add_str(fd, COL_PROTOCOL, "NBSS (TCP)");
1484 if (check_col(fd, COL_INFO)) {
1485 col_add_fstr(fd, COL_INFO, "NBSS (TCP) Continuation Message");
1489 proto_tree_add_text(tree, offset, max_data, "Continuation data");
1495 if (check_col(fd, COL_PROTOCOL))
1496 col_add_str(fd, COL_PROTOCOL, "NBSS (TCP)");
1497 if (check_col(fd, COL_INFO)) {
1498 col_add_fstr(fd, COL_INFO,
1499 val_to_str(msg_type, message_types, "Unknown (%x)"));
1502 while (max_data > 0) {
1503 len = dissect_nbss_packet(pd, offset, fd, tree, max_data);
1511 proto_register_nbt(void)
1513 /* static hf_register_info hf[] = {
1515 { "Name", "nbipx.abbreviation", TYPE, VALS_POINTER }},
1518 proto_nbns = proto_register_protocol("NetBIOS Name Service", "nbns");
1519 proto_nbdgm = proto_register_protocol("NetBIOS Datagram Service", "nbdgm");
1520 proto_nbss = proto_register_protocol("NetBIOS Session Service", "nbss");
1521 /* proto_register_field_array(proto_nbipx, hf, array_length(hf));*/