2 * Routines for NetBIOS Name Service, Datagram Service, and Session Service
3 * packet disassembly (the name dates back 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.23 1999/07/29 05:46:58 gram 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"
44 static int proto_nbns = -1;
45 static int proto_nbdgm = -1;
46 static int proto_nbss = -1;
48 /* Packet structure taken from RFC 1002. See also RFC 1001.
49 * Opcode, flags, and rcode treated as "flags", similarly to DNS,
50 * to make it easier to lift the dissection code from "packet-dns.c". */
52 /* Offsets of fields in the NBNS header. */
60 /* Length of NBNS header. */
61 #define NBNS_HDRLEN 12
64 #define T_NB 32 /* NetBIOS name service RR */
65 #define T_NBSTAT 33 /* NetBIOS node status RR */
67 /* Bit fields in the flags */
68 #define F_RESPONSE (1<<15) /* packet is response */
69 #define F_OPCODE (0xF<<11) /* query opcode */
70 #define F_AUTHORITATIVE (1<<10) /* response is authoritative */
71 #define F_TRUNCATED (1<<9) /* response is truncated */
72 #define F_RECDESIRED (1<<8) /* recursion desired */
73 #define F_RECAVAIL (1<<7) /* recursion available */
74 #define F_BROADCAST (1<<4) /* broadcast/multicast packet */
75 #define F_RCODE (0xF<<0) /* reply code */
78 #define OPCODE_QUERY (0<<11) /* standard query */
79 #define OPCODE_REGISTRATION (5<<11) /* registration */
80 #define OPCODE_RELEASE (6<<11) /* release name */
81 #define OPCODE_WACK (7<<11) /* wait for acknowledgement */
82 #define OPCODE_REFRESH (8<<11) /* refresh registration */
83 #define OPCODE_REFRESHALT (9<<11) /* refresh registration (alternate opcode) */
84 #define OPCODE_MHREGISTRATION (15<<11) /* multi-homed registration */
87 #define RCODE_NOERROR (0<<0)
88 #define RCODE_FMTERROR (1<<0)
89 #define RCODE_SERVFAIL (2<<0)
90 #define RCODE_NAMEERROR (3<<0)
91 #define RCODE_NOTIMPL (4<<0)
92 #define RCODE_REFUSED (5<<0)
93 #define RCODE_ACTIVE (6<<0)
94 #define RCODE_CONFLICT (7<<0)
96 /* Values for the "NB_FLAGS" field of RR data. From RFC 1001 and 1002,
97 * except for NB_FLAGS_ONT_H_NODE, which was discovered by looking at
99 #define NB_FLAGS_ONT (3<<(15-2)) /* bits for node type */
100 #define NB_FLAGS_ONT_B_NODE (0<<(15-2)) /* B-mode node */
101 #define NB_FLAGS_ONT_P_NODE (1<<(15-2)) /* P-mode node */
102 #define NB_FLAGS_ONT_M_NODE (2<<(15-2)) /* M-mode node */
103 #define NB_FLAGS_ONT_H_NODE (3<<(15-2)) /* H-mode node */
105 #define NB_FLAGS_G (1<<(15-0)) /* group name */
107 /* Values for the "NAME_FLAGS" field of a NODE_NAME entry in T_NBSTAT
108 * RR data. From RFC 1001 and 1002, except for NAME_FLAGS_ONT_H_NODE,
109 * which was discovered by looking at packet traces. */
110 #define NAME_FLAGS_PRM (1<<(15-6)) /* name is permanent node name */
112 #define NAME_FLAGS_ACT (1<<(15-5)) /* name is active */
114 #define NAME_FLAGS_CNF (1<<(15-4)) /* name is in conflict */
116 #define NAME_FLAGS_DRG (1<<(15-3)) /* name is being deregistered */
118 #define NAME_FLAGS_ONT (3<<(15-2)) /* bits for node type */
119 #define NAME_FLAGS_ONT_B_NODE (0<<(15-2)) /* B-mode node */
120 #define NAME_FLAGS_ONT_P_NODE (1<<(15-2)) /* P-mode node */
121 #define NAME_FLAGS_ONT_M_NODE (2<<(15-2)) /* M-mode node */
123 #define NAME_FLAGS_G (1<<(15-0)) /* group name */
125 static const value_string opcode_vals[] = {
126 { OPCODE_QUERY, "Name query" },
127 { OPCODE_REGISTRATION, "Registration" },
128 { OPCODE_RELEASE, "Release" },
129 { OPCODE_WACK, "Wait for acknowledgment" },
130 { OPCODE_REFRESH, "Refresh" },
131 { OPCODE_REFRESHALT, "Refresh (alternate opcode)" },
132 { OPCODE_MHREGISTRATION, "Multi-homed registration" },
137 nbns_type_name (int type)
149 /* "Canonicalize" a 16-character NetBIOS name by:
151 * removing and saving the last byte;
153 * stripping trailing blanks;
155 * appending the trailing byte, as a hex number, in square brackets. */
157 canonicalize_netbios_name(char *nbname)
162 /* Get the last character of the name, as it's a special number
163 * indicating the type of the name, rather than part of the name
165 pnbname = nbname + 15; /* point to the 16th character */
166 lastchar = *(unsigned char *)pnbname;
168 /* Now strip off any trailing blanks used to pad it to
170 while (pnbname > &nbname[0]) {
171 if (*(pnbname - 1) != ' ')
172 break; /* found non-blank character */
173 pnbname--; /* blank - skip over it */
176 /* Replace the last character with its hex value, in square
177 * brackets, to make it easier to tell what it is. */
178 sprintf(pnbname, "[%02X]", lastchar);
184 get_nbns_name(const u_char *nbns_data_ptr, const u_char *pd,
185 int offset, char *name_ret)
189 char nbname[MAXDNAME+4]; /* 4 for [<last char>] */
190 char *pname, *pnbname, cname, cnbname;
192 name_len = get_dns_name(nbns_data_ptr, pd + offset, name, sizeof(name));
194 /* OK, now undo the first-level encoding. */
196 pnbname = &nbname[0];
198 /* Every two characters of the first level-encoded name
199 * turn into one character in the decoded name. */
202 break; /* no more characters */
204 break; /* scope ID follows */
205 if (cname < 'A' || cname > 'Z') {
208 "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
212 cnbname = cname << 4;
216 if (cname == '\0' || cname == '.') {
217 /* No more characters in the name - but we're in
218 * the middle of a pair. Not legal. */
220 "Illegal NetBIOS name (odd number of bytes)");
223 if (cname < 'A' || cname > 'Z') {
226 "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
233 /* Store the character. */
234 *pnbname++ = cnbname;
237 /* NetBIOS names are supposed to be exactly 16 bytes long. */
238 if (pnbname - nbname == 16) {
239 /* This one is; canonicalize its name. */
240 pnbname = canonicalize_netbios_name(nbname);
242 sprintf(nbname, "Illegal NetBIOS name (%ld bytes long)",
243 (long)(pnbname - nbname));
247 /* We have a scope ID, starting at "pname"; append that to
248 * the decoded host name. */
249 strcpy(pnbname, pname);
251 /* Terminate the decoded host name. */
256 strcpy (name_ret, nbname);
262 get_nbns_name_type_class(const u_char *nbns_data_ptr, const u_char *pd,
263 int offset, char *name_ret, int *name_len_ret, int *type_ret,
270 name_len = get_nbns_name(nbns_data_ptr, pd, offset, name_ret);
273 type = pntohs(&pd[offset]);
275 class = pntohs(&pd[offset]);
279 *name_len_ret = name_len;
286 dissect_nbns_query(const u_char *nbns_data_ptr, const u_char *pd, int offset,
287 proto_tree *nbns_tree)
297 const u_char *data_start;
301 data_start = dptr = pd + offset;
303 len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
304 &name_len, &type, &class);
307 type_name = nbns_type_name(type);
308 class_name = dns_class_name(class);
310 tq = proto_tree_add_text(nbns_tree, offset, len, "%s: type %s, class %s",
311 name, type_name, class_name);
312 q_tree = proto_item_add_subtree(tq, ETT_NBNS_QD);
314 proto_tree_add_text(q_tree, offset, name_len, "Name: %s", name);
317 proto_tree_add_text(q_tree, offset, 2, "Type: %s", type_name);
320 proto_tree_add_text(q_tree, offset, 2, "Class: %s", class_name);
323 return dptr - data_start;
327 nbns_add_nbns_flags(proto_tree *nbns_tree, int offset, u_short flags,
331 proto_tree *field_tree;
333 static const value_string rcode_vals[] = {
334 { RCODE_NOERROR, "No error" },
335 { RCODE_FMTERROR, "Request was invalidly formatted" },
336 { RCODE_SERVFAIL, "Server failure" },
337 { RCODE_NAMEERROR, "Requested name does not exist" },
338 { RCODE_NOTIMPL, "Request is not implemented" },
339 { RCODE_REFUSED, "Request was refused" },
340 { RCODE_ACTIVE, "Name is owned by another node" },
341 { RCODE_CONFLICT, "Name is in conflict" },
345 strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals,
346 "Unknown operation"));
347 if (flags & F_RESPONSE && !is_wack) {
348 strcat(buf, " response");
350 strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
353 tf = proto_tree_add_text(nbns_tree, offset, 2,
354 "Flags: 0x%04x (%s)", flags, buf);
355 field_tree = proto_item_add_subtree(tf, ETT_NBNS_FLAGS);
356 proto_tree_add_text(field_tree, offset, 2, "%s",
357 decode_boolean_bitfield(flags, F_RESPONSE,
358 2*8, "Response", "Query"));
359 proto_tree_add_text(field_tree, offset, 2, "%s",
360 decode_enumerated_bitfield(flags, F_OPCODE,
361 2*8, opcode_vals, "%s"));
362 if (flags & F_RESPONSE) {
363 proto_tree_add_text(field_tree, offset, 2,
365 decode_boolean_bitfield(flags, F_AUTHORITATIVE,
367 "Server is an authority for domain",
368 "Server isn't an authority for domain"));
370 proto_tree_add_text(field_tree, offset, 2, "%s",
371 decode_boolean_bitfield(flags, F_TRUNCATED,
373 "Message is truncated",
374 "Message is not truncated"));
375 proto_tree_add_text(field_tree, offset, 2, "%s",
376 decode_boolean_bitfield(flags, F_RECDESIRED,
378 "Do query recursively",
379 "Don't do query recursively"));
380 if (flags & F_RESPONSE) {
381 proto_tree_add_text(field_tree, offset, 2,
383 decode_boolean_bitfield(flags, F_RECAVAIL,
385 "Server can do recursive queries",
386 "Server can't do recursive queries"));
388 proto_tree_add_text(field_tree, offset, 2, "%s",
389 decode_boolean_bitfield(flags, F_BROADCAST,
392 "Not a broadcast packet"));
393 if (flags & F_RESPONSE && !is_wack) {
394 proto_tree_add_text(field_tree, offset, 2,
396 decode_enumerated_bitfield(flags, F_RCODE,
403 nbns_add_nb_flags(proto_tree *rr_tree, int offset, u_short flags)
406 proto_tree *field_tree;
408 static const value_string nb_flags_ont_vals[] = {
409 { NB_FLAGS_ONT_B_NODE, "B-node" },
410 { NB_FLAGS_ONT_P_NODE, "P-node" },
411 { NB_FLAGS_ONT_M_NODE, "M-node" },
412 { NB_FLAGS_ONT_H_NODE, "H-node" },
416 strcpy(buf, val_to_str(flags & NB_FLAGS_ONT, nb_flags_ont_vals,
419 if (flags & NB_FLAGS_G)
420 strcat(buf, "group");
422 strcat(buf, "unique");
423 tf = proto_tree_add_text(rr_tree, offset, 2, "Flags: 0x%x (%s)", flags,
425 field_tree = proto_item_add_subtree(tf, ETT_NBNS_NB_FLAGS);
426 proto_tree_add_text(field_tree, offset, 2, "%s",
427 decode_boolean_bitfield(flags, NB_FLAGS_G,
431 proto_tree_add_text(field_tree, offset, 2, "%s",
432 decode_enumerated_bitfield(flags, NB_FLAGS_ONT,
433 2*8, nb_flags_ont_vals, "%s"));
437 nbns_add_name_flags(proto_tree *rr_tree, int offset, u_short flags)
440 proto_item *field_tree;
442 static const value_string name_flags_ont_vals[] = {
443 { NAME_FLAGS_ONT_B_NODE, "B-node" },
444 { NAME_FLAGS_ONT_P_NODE, "P-node" },
445 { NAME_FLAGS_ONT_M_NODE, "M-node" },
449 strcpy(buf, val_to_str(flags & NAME_FLAGS_ONT, name_flags_ont_vals,
452 if (flags & NAME_FLAGS_G)
453 strcat(buf, "group");
455 strcat(buf, "unique");
456 if (flags & NAME_FLAGS_DRG)
457 strcat(buf, ", being deregistered");
458 if (flags & NAME_FLAGS_CNF)
459 strcat(buf, ", in conflict");
460 if (flags & NAME_FLAGS_ACT)
461 strcat(buf, ", active");
462 if (flags & NAME_FLAGS_PRM)
463 strcat(buf, ", permanent node name");
464 tf = proto_tree_add_text(rr_tree, offset, 2, "Name flags: 0x%x (%s)",
466 field_tree = proto_item_add_subtree(tf, ETT_NBNS_NAME_FLAGS);
467 proto_tree_add_text(field_tree, offset, 2, "%s",
468 decode_boolean_bitfield(flags, NAME_FLAGS_G,
472 proto_tree_add_text(field_tree, offset, 2, "%s",
473 decode_enumerated_bitfield(flags, NAME_FLAGS_ONT,
474 2*8, name_flags_ont_vals, "%s"));
475 proto_tree_add_text(field_tree, offset, 2, "%s",
476 decode_boolean_bitfield(flags, NAME_FLAGS_DRG,
478 "Name is being deregistered",
479 "Name is not being deregistered"));
480 proto_tree_add_text(field_tree, offset, 2, "%s",
481 decode_boolean_bitfield(flags, NAME_FLAGS_CNF,
483 "Name is in conflict",
484 "Name is not in conflict"));
485 proto_tree_add_text(field_tree, offset, 2, "%s",
486 decode_boolean_bitfield(flags, NAME_FLAGS_ACT,
489 "Name is not active"));
490 proto_tree_add_text(field_tree, offset, 2, "%s",
491 decode_boolean_bitfield(flags, NAME_FLAGS_PRM,
493 "Permanent node name",
494 "Not permanent node name"));
498 dissect_nbns_answer(const u_char *nbns_data_ptr, const u_char *pd, int offset,
499 proto_tree *nbns_tree, int opcode)
509 const u_char *data_start;
516 data_start = dptr = pd + offset;
518 len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
519 &name_len, &type, &class);
522 type_name = nbns_type_name(type);
523 class_name = dns_class_name(class);
528 data_len = pntohs(dptr);
532 case T_NB: /* "NB" record */
533 trr = proto_tree_add_text(nbns_tree, offset,
534 (dptr - data_start) + data_len,
535 "%s: type %s, class %s",
536 name, type_name, class_name);
537 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
538 name_len, type_name, class_name, ttl, data_len);
539 offset += (dptr - data_start);
540 while (data_len > 0) {
541 if (opcode == OPCODE_WACK) {
542 /* WACK response. This doesn't contain the
543 * same type of RR data as other T_NB
546 proto_tree_add_text(rr_tree, offset,
547 data_len, "(incomplete entry)");
550 flags = pntohs(dptr);
552 nbns_add_nbns_flags(rr_tree, offset, flags, 1);
557 proto_tree_add_text(rr_tree, offset,
558 data_len, "(incomplete entry)");
561 flags = pntohs(dptr);
563 nbns_add_nb_flags(rr_tree, offset, flags);
568 proto_tree_add_text(rr_tree, offset,
569 data_len, "(incomplete entry)");
572 proto_tree_add_text(rr_tree, offset, 4,
574 ip_to_str((guint8 *)dptr));
582 case T_NBSTAT: /* "NBSTAT" record */
585 char nbname[16+4+1]; /* 4 for [<last char>] */
588 trr = proto_tree_add_text(nbns_tree, offset,
589 (dptr - data_start) + data_len,
590 "%s: type %s, class %s",
591 name, type_name, class_name);
592 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
593 name_len, type_name, class_name, ttl, data_len);
594 offset += (dptr - data_start);
596 proto_tree_add_text(rr_tree, offset,
597 data_len, "(incomplete entry)");
602 proto_tree_add_text(rr_tree, offset, 2,
603 "Number of names: %u", num_names);
606 while (num_names != 0) {
608 proto_tree_add_text(rr_tree, offset,
609 data_len, "(incomplete entry)");
612 memcpy(nbname, dptr, 16);
614 canonicalize_netbios_name(nbname);
615 proto_tree_add_text(rr_tree, offset, 16,
621 proto_tree_add_text(rr_tree, offset,
622 data_len, "(incomplete entry)");
625 name_flags = pntohs(dptr);
627 nbns_add_name_flags(rr_tree, offset, name_flags);
635 proto_tree_add_text(rr_tree, offset,
636 data_len, "(incomplete entry)");
639 proto_tree_add_text(rr_tree, offset, 6,
641 ether_to_str((guint8 *)dptr));
647 proto_tree_add_text(rr_tree, offset,
648 data_len, "(incomplete entry)");
651 proto_tree_add_text(rr_tree, offset, 1,
652 "Jumpers: 0x%x", *dptr);
658 proto_tree_add_text(rr_tree, offset,
659 data_len, "(incomplete entry)");
662 proto_tree_add_text(rr_tree, offset, 1,
663 "Test result: 0x%x", *dptr);
669 proto_tree_add_text(rr_tree, offset,
670 data_len, "(incomplete entry)");
673 proto_tree_add_text(rr_tree, offset, 2,
674 "Version number: 0x%x", pntohs(dptr));
680 proto_tree_add_text(rr_tree, offset,
681 data_len, "(incomplete entry)");
684 proto_tree_add_text(rr_tree, offset, 2,
685 "Period of statistics: 0x%x", pntohs(dptr));
691 proto_tree_add_text(rr_tree, offset,
692 data_len, "(incomplete entry)");
695 proto_tree_add_text(rr_tree, offset, 2,
696 "Number of CRCs: %u", pntohs(dptr));
702 proto_tree_add_text(rr_tree, offset,
703 data_len, "(incomplete entry)");
706 proto_tree_add_text(rr_tree, offset, 2,
707 "Number of alignment errors: %u", pntohs(dptr));
713 proto_tree_add_text(rr_tree, offset,
714 data_len, "(incomplete entry)");
717 proto_tree_add_text(rr_tree, offset, 2,
718 "Number of collisions: %u", pntohs(dptr));
724 proto_tree_add_text(rr_tree, offset,
725 data_len, "(incomplete entry)");
728 proto_tree_add_text(rr_tree, offset, 2,
729 "Number of send aborts: %u", pntohs(dptr));
735 proto_tree_add_text(rr_tree, offset,
736 data_len, "(incomplete entry)");
739 proto_tree_add_text(rr_tree, offset, 4,
740 "Number of good sends: %u", pntohl(dptr));
746 proto_tree_add_text(rr_tree, offset,
747 data_len, "(incomplete entry)");
750 proto_tree_add_text(rr_tree, offset, 4,
751 "Number of good receives: %u", pntohl(dptr));
757 proto_tree_add_text(rr_tree, offset,
758 data_len, "(incomplete entry)");
761 proto_tree_add_text(rr_tree, offset, 2,
762 "Number of retransmits: %u", pntohs(dptr));
768 proto_tree_add_text(rr_tree, offset,
769 data_len, "(incomplete entry)");
772 proto_tree_add_text(rr_tree, offset, 2,
773 "Number of no resource conditions: %u", pntohs(dptr));
779 proto_tree_add_text(rr_tree, offset,
780 data_len, "(incomplete entry)");
783 proto_tree_add_text(rr_tree, offset, 2,
784 "Number of command blocks: %u", pntohs(dptr));
790 proto_tree_add_text(rr_tree, offset,
791 data_len, "(incomplete entry)");
794 proto_tree_add_text(rr_tree, offset, 2,
795 "Number of pending sessions: %u", pntohs(dptr));
801 proto_tree_add_text(rr_tree, offset,
802 data_len, "(incomplete entry)");
805 proto_tree_add_text(rr_tree, offset, 2,
806 "Max number of pending sessions: %u", pntohs(dptr));
810 proto_tree_add_text(rr_tree, offset, 2,
811 "Max total sessions possible: %u", pntohs(dptr));
817 proto_tree_add_text(rr_tree, offset,
818 data_len, "(incomplete entry)");
821 proto_tree_add_text(rr_tree, offset, 2,
822 "Session data packet size: %u", pntohs(dptr));
831 trr = proto_tree_add_text(nbns_tree, offset,
832 (dptr - data_start) + data_len,
833 "%s: type %s, class %s",
834 name, type_name, class_name);
835 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
836 name_len, type_name, class_name, ttl, data_len);
837 offset += (dptr - data_start);
838 proto_tree_add_text(rr_tree, offset, data_len, "Data");
843 return dptr - data_start;
847 dissect_query_records(const u_char *nbns_data_ptr, int count, const u_char *pd,
848 int cur_off, proto_tree *nbns_tree)
855 ti = proto_tree_add_text(nbns_tree, start_off, 0, "Queries");
856 qatree = proto_item_add_subtree(ti, ETT_NBNS_QRY);
858 cur_off += dissect_nbns_query(nbns_data_ptr, pd, cur_off, qatree);
859 proto_item_set_len(ti, cur_off - start_off);
861 return cur_off - start_off;
867 dissect_answer_records(const u_char *nbns_data_ptr, int count,
868 const u_char *pd, int cur_off, proto_tree *nbns_tree, int opcode, char *name)
875 ti = proto_tree_add_text(nbns_tree, start_off, 0, name);
876 qatree = proto_item_add_subtree(ti, ETT_NBNS_ANS);
878 cur_off += dissect_nbns_answer(nbns_data_ptr, pd, cur_off,
880 proto_item_set_len(ti, cur_off - start_off);
881 return cur_off - start_off;
885 dissect_nbns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
887 const u_char *nbns_data_ptr;
888 proto_tree *nbns_tree;
890 guint16 id, flags, quest, ans, auth, add;
893 nbns_data_ptr = &pd[offset];
895 /* To do: check for runts, errs, etc. */
896 id = pntohs(&pd[offset + NBNS_ID]);
897 flags = pntohs(&pd[offset + NBNS_FLAGS]);
898 quest = pntohs(&pd[offset + NBNS_QUEST]);
899 ans = pntohs(&pd[offset + NBNS_ANS]);
900 auth = pntohs(&pd[offset + NBNS_AUTH]);
901 add = pntohs(&pd[offset + NBNS_ADD]);
903 if (check_col(fd, COL_PROTOCOL))
904 col_add_str(fd, COL_PROTOCOL, "NBNS (UDP)");
905 if (check_col(fd, COL_INFO)) {
906 col_add_fstr(fd, COL_INFO, "%s%s",
907 val_to_str(flags & F_OPCODE, opcode_vals,
908 "Unknown operation (%x)"),
909 (flags & F_RESPONSE) ? " response" : "");
913 ti = proto_tree_add_item(tree, proto_nbns, offset, END_OF_FRAME, NULL);
914 nbns_tree = proto_item_add_subtree(ti, ETT_NBNS);
916 proto_tree_add_text(nbns_tree, offset + NBNS_ID, 2,
917 "Transaction ID: 0x%04X", id);
919 nbns_add_nbns_flags(nbns_tree, offset + NBNS_FLAGS, flags, 0);
920 proto_tree_add_text(nbns_tree, offset + NBNS_QUEST, 2,
923 proto_tree_add_text(nbns_tree, offset + NBNS_ANS, 2,
926 proto_tree_add_text(nbns_tree, offset + NBNS_AUTH, 2,
929 proto_tree_add_text(nbns_tree, offset + NBNS_ADD, 2,
930 "Additional RRs: %d",
933 cur_off = offset + NBNS_HDRLEN;
936 cur_off += dissect_query_records(nbns_data_ptr,
937 quest, pd, cur_off, nbns_tree);
940 cur_off += dissect_answer_records(nbns_data_ptr,
941 ans, pd, cur_off, nbns_tree,
946 cur_off += dissect_answer_records(nbns_data_ptr,
947 auth, pd, cur_off, nbns_tree,
949 "Authoritative nameservers");
952 cur_off += dissect_answer_records(nbns_data_ptr,
953 add, pd, cur_off, nbns_tree,
955 "Additional records");
959 /* NetBIOS datagram packet, from RFC 1002, page 32 */
960 struct nbdgm_header {
971 /* For packets with data */
975 /* For error packets */
980 dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
983 proto_tree *nbdgm_tree = NULL;
985 struct nbdgm_header header;
991 "Direct_unique datagram",
992 "Direct_group datagram",
993 "Broadcast datagram",
995 "Datagram query request",
996 "Datagram positive query response",
997 "Datagram negative query response"
1007 static value_string error_codes[] = {
1008 { 0x82, "Destination name not present" },
1009 { 0x83, "Invalid source name format" },
1010 { 0x84, "Invalid destination name format" },
1014 char *yesno[] = { "No", "Yes" };
1016 char name[MAXDNAME+4];
1019 header.msg_type = pd[offset];
1021 flags = pd[offset+1];
1022 header.flags.more = flags & 1;
1023 header.flags.first = (flags & 2) >> 1;
1024 header.flags.node_type = (flags & 12) >> 2;
1026 header.dgm_id = pntohs(&pd[offset+2]);
1027 memcpy(&header.src_ip, &pd[offset+4], 4);
1028 header.src_port = pntohs(&pd[offset+8]);
1030 if (header.msg_type == 0x10 ||
1031 header.msg_type == 0x11 || header.msg_type == 0x12) {
1032 header.dgm_length = pntohs(&pd[offset+10]);
1033 header.pkt_offset = pntohs(&pd[offset+12]);
1035 else if (header.msg_type == 0x13) {
1036 header.error_code = pntohs(&pd[offset+10]);
1039 message_index = header.msg_type - 0x0f;
1040 if (message_index < 1 || message_index > 8) {
1044 if (check_col(fd, COL_PROTOCOL))
1045 col_add_str(fd, COL_PROTOCOL, "NBDS (UDP)");
1046 if (check_col(fd, COL_INFO)) {
1047 col_add_fstr(fd, COL_INFO, "%s", message[message_index]);
1051 ti = proto_tree_add_item(tree, proto_nbdgm, offset, header.dgm_length, NULL);
1052 nbdgm_tree = proto_item_add_subtree(ti, ETT_NBDGM);
1054 proto_tree_add_text(nbdgm_tree, offset, 1, "Message Type: %s",
1055 message[message_index]);
1056 proto_tree_add_text(nbdgm_tree, offset+1, 1, "More fragments follow: %s",
1057 yesno[header.flags.more]);
1058 proto_tree_add_text(nbdgm_tree, offset+1, 1, "This is first fragment: %s",
1059 yesno[header.flags.first]);
1060 proto_tree_add_text(nbdgm_tree, offset+1, 1, "Node Type: %s",
1061 node[header.flags.node_type]);
1063 proto_tree_add_text(nbdgm_tree, offset+2, 2, "Datagram ID: 0x%04X",
1065 proto_tree_add_text(nbdgm_tree, offset+4, 4, "Source IP: %s",
1066 ip_to_str((guint8 *)&header.src_ip));
1067 proto_tree_add_text(nbdgm_tree, offset+8, 2, "Source Port: %d",
1074 if (header.msg_type == 0x10 ||
1075 header.msg_type == 0x11 || header.msg_type == 0x12) {
1078 proto_tree_add_text(nbdgm_tree, offset, 2,
1079 "Datagram length: %d bytes", header.dgm_length);
1080 proto_tree_add_text(nbdgm_tree, offset+2, 2,
1081 "Packet offset: %d bytes", header.pkt_offset);
1088 len = get_nbns_name(&pd[offset], pd, offset, name);
1091 proto_tree_add_text(nbdgm_tree, offset, len, "Source name: %s",
1097 /* Destination name */
1098 len = get_nbns_name(&pd[offset], pd, offset, name);
1101 proto_tree_add_text(nbdgm_tree, offset, len, "Destination name: %s",
1107 /* here we can pass the packet off to the next protocol */
1108 dissect_smb(pd, offset, fd, tree, max_data);
1110 else if (header.msg_type == 0x13) {
1112 proto_tree_add_text(nbdgm_tree, offset, 1, "Error code: %s",
1113 val_to_str(header.error_code, error_codes, "Unknown (0x%x)"));
1116 else if (header.msg_type == 0x14 ||
1117 header.msg_type == 0x15 || header.msg_type == 0x16) {
1118 /* Destination name */
1119 len = get_nbns_name(&pd[offset], pd, offset, name);
1122 proto_tree_add_text(nbdgm_tree, offset, len, "Destination name: %s",
1129 * NetBIOS Session Service message types.
1131 #define SESSION_MESSAGE 0x00
1132 #define SESSION_REQUEST 0x81
1133 #define POSITIVE_SESSION_RESPONSE 0x82
1134 #define NEGATIVE_SESSION_RESPONSE 0x83
1135 #define RETARGET_SESSION_RESPONSE 0x84
1136 #define SESSION_KEEP_ALIVE 0x85
1138 static const value_string message_types[] = {
1139 { SESSION_MESSAGE, "Session message" },
1140 { SESSION_REQUEST, "Session request" },
1141 { POSITIVE_SESSION_RESPONSE, "Positive session response" },
1142 { NEGATIVE_SESSION_RESPONSE, "Negative session response" },
1143 { RETARGET_SESSION_RESPONSE, "Retarget session response" },
1144 { SESSION_KEEP_ALIVE, "Session keep-alive" },
1149 * NetBIOS Session Service flags.
1151 #define NBSS_FLAGS_E 0x1
1153 static const value_string error_codes[] = {
1154 { 0x80, "Not listening on called name" },
1155 { 0x81, "Not listening for called name" },
1156 { 0x82, "Called name not present" },
1157 { 0x83, "Called name present, but insufficient resources" },
1158 { 0x8F, "Unspecified error" },
1163 * Dissect a single NBSS packet (there may be more than one in a given TCP
1164 * segment). Hmmm, in my experience, I have never seen more than one NBSS
1165 * in a single segment, since they mostly contain SMBs which are essentially
1166 * a request response type protocol (RJS). Also, a single session message
1167 * may be split over multiple segments.
1170 dissect_nbss_packet(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int max_data)
1172 proto_tree *nbss_tree = NULL;
1174 proto_tree *field_tree;
1180 char name[MAXDNAME+4];
1182 msg_type = pd[offset];
1183 flags = pd[offset + 1];
1184 length = pntohs(&pd[offset + 2]);
1185 if (flags & NBSS_FLAGS_E)
1189 ti = proto_tree_add_item(tree, proto_nbss, offset, length + 4, NULL);
1190 nbss_tree = proto_item_add_subtree(ti, ETT_NBSS);
1192 proto_tree_add_text(nbss_tree, offset, 1, "Message Type: %s",
1193 val_to_str(msg_type, message_types, "Unknown (%x)"));
1199 tf = proto_tree_add_text(nbss_tree, offset, 1, "Flags: 0x%04x", flags);
1200 field_tree = proto_item_add_subtree(tf, ETT_NBSS_FLAGS);
1201 proto_tree_add_text(field_tree, offset, 1, "%s",
1202 decode_boolean_bitfield(flags, NBSS_FLAGS_E,
1203 8, "Add 65536 to length", "Add 0 to length"));
1209 proto_tree_add_text(nbss_tree, offset, 2, "Length: %u", length);
1216 case SESSION_REQUEST:
1217 len = get_nbns_name(&pd[offset], pd, offset, name);
1219 proto_tree_add_text(nbss_tree, offset, len,
1220 "Called name: %s", name);
1223 len = get_nbns_name(&pd[offset], pd, offset, name);
1226 proto_tree_add_text(nbss_tree, offset, len,
1227 "Calling name: %s", name);
1231 case NEGATIVE_SESSION_RESPONSE:
1233 proto_tree_add_text(nbss_tree, offset, 1,
1235 val_to_str(pd[offset], error_codes, "Unknown (%x)"));
1238 case RETARGET_SESSION_RESPONSE:
1240 proto_tree_add_text(nbss_tree, offset, 4,
1241 "Retarget IP address: %s",
1242 ip_to_str((guint8 *)&pd[offset]));
1247 proto_tree_add_text(nbss_tree, offset, 2,
1248 "Retarget port: %u", pntohs(&pd[offset]));
1252 case SESSION_MESSAGE:
1254 * Here we can pass the packet off to the next protocol.
1257 dissect_smb(pd, offset, fd, tree, max_data - 4);
1266 dissect_nbss(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int max_data)
1273 msg_type = pd[offset];
1274 flags = pd[offset + 1];
1275 length = pntohs(&pd[offset + 2]);
1276 if (flags & NBSS_FLAGS_E)
1279 if (check_col(fd, COL_PROTOCOL))
1280 col_add_str(fd, COL_PROTOCOL, "NBSS (TCP)");
1281 if (check_col(fd, COL_INFO)) {
1282 col_add_fstr(fd, COL_INFO,
1283 val_to_str(msg_type, message_types, "Unknown (%x)"));
1286 while (max_data > 0) {
1287 len = dissect_nbss_packet(pd, offset, fd, tree, max_data);
1295 proto_register_nbt(void)
1297 /* static hf_register_info hf[] = {
1299 { "Name", "nbipx.abbreviation", TYPE, VALS_POINTER }},
1302 proto_nbns = proto_register_protocol("NetBIOS Name Service", "nbns");
1303 proto_nbdgm = proto_register_protocol("NetBIOS Datagram Service", "nbdgm");
1304 proto_nbss = proto_register_protocol("NetBIOS Session Service", "nbss");
1305 /* proto_register_field_array(proto_nbipx, hf, array_length(hf));*/