2 * Routines for NetBIOS Name Service packet disassembly
3 * Gilbert Ramirez <gram@verdict.uthscsa.edu>
4 * Much stuff added by Guy Harris <guy@netapp.com>
6 * $Id: packet-nbns.c,v 1.8 1998/11/20 05:54:08 gram Exp $
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@zing.org>
10 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 #ifdef HAVE_SYS_TYPES_H
38 # include <sys/types.h>
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
47 #include "packet-dns.h"
49 /* Packet structure taken from RFC 1002. See also RFC 1001.
50 * The Samba source code, specifically nmblib.c, also helps a lot. */
59 guint8 recursion_available;
60 guint8 recursion_desired;
72 #define T_NB 32 /* NetBIOS name service RR */
73 #define T_NBSTAT 33 /* NetBIOS node status RR */
75 /* NetBIOS datagram packet, from RFC 1002, page 32 */
87 /* For packets with data */
91 /* For error packets */
97 nbns_type_name (int type)
109 /* "Canonicalize" a 16-character NetBIOS name by:
111 * removing and saving the last byte;
113 * stripping trailing blanks;
115 * appending the trailing byte, as a hex number, in square brackets. */
117 canonicalize_netbios_name(char *nbname)
122 /* Get the last character of the name, as it's a special number
123 * indicating the type of the name, rather than part of the name
125 pnbname = nbname + 15; /* point to the 16th character */
126 lastchar = *(unsigned char *)pnbname;
128 /* Now strip off any trailing blanks used to pad it to
130 while (pnbname > &nbname[0]) {
131 if (*(pnbname - 1) != ' ')
132 break; /* found non-blank character */
133 pnbname--; /* blank - skip over it */
136 /* Replace the last character with its hex value, in square
137 * brackets, to make it easier to tell what it is. */
138 sprintf(pnbname, "[%02X]", lastchar);
144 get_nbns_name_type_class(const u_char *nbns_data_ptr, const u_char *pd,
145 int offset, char *name_ret, int *name_len_ret, int *type_ret,
153 char nbname[MAXDNAME+4]; /* 4 for [<last char>] */
154 char *pname, *pnbname, cname, cnbname;
155 const u_char *pd_save;
157 name_len = get_dns_name(nbns_data_ptr, pd, offset, name, sizeof(name));
167 /* OK, now undo the first-level encoding. */
169 pnbname = &nbname[0];
171 /* Every two characters of the first level-encoded name
172 * turn into one character in the decoded name. */
175 break; /* no more characters */
177 break; /* scope ID follows */
178 if (cname < 'A' || cname > 'Z') {
181 "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
185 cnbname = cname << 4;
189 if (cname == '\0' || cname == '.') {
190 /* No more characters in the name - but we're in
191 * the middle of a pair. Not legal. */
193 "Illegal NetBIOS name (odd number of bytes)");
196 if (cname < 'A' || cname > 'Z') {
199 "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
206 /* Store the character. */
207 *pnbname++ = cnbname;
210 /* NetBIOS names are supposed to be exactly 16 bytes long. */
211 if (pnbname - nbname == 16) {
212 /* This one is; canonicalize its name. */
213 pnbname = canonicalize_netbios_name(nbname);
215 sprintf(nbname, "Illegal NetBIOS name (%ld bytes long)",
216 (long)(pnbname - nbname));
220 /* We have a scope ID, starting at "pname"; append that to
221 * the decoded host name. */
222 strcpy(pnbname, pname);
224 /* Terminate the decoded host name. */
229 strcpy (name_ret, nbname);
232 *name_len_ret = name_len;
240 dissect_nbns_query(const u_char *nbns_data_ptr, const u_char *pd, int offset,
241 GtkWidget *nbns_tree)
251 const u_char *data_start;
252 GtkWidget *q_tree, *tq;
254 data_start = dptr = pd + offset;
256 len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
257 &name_len, &type, &class);
260 type_name = nbns_type_name(type);
261 class_name = dns_class_name(class);
263 tq = add_item_to_tree(nbns_tree, offset, len, "%s: type %s, class %s",
264 name, type_name, class_name);
265 q_tree = gtk_tree_new();
266 add_subtree(tq, q_tree, ETT_NBNS_QD);
268 add_item_to_tree(q_tree, offset, name_len, "Name: %s", name);
271 add_item_to_tree(q_tree, offset, 2, "Type: %s", type_name);
274 add_item_to_tree(q_tree, offset, 2, "Class: %s", class_name);
277 return dptr - data_start;
282 dissect_nbns_answer(const u_char *nbns_data_ptr, const u_char *pd, int offset,
283 GtkWidget *nbns_tree, int opcode)
293 const u_char *data_start;
297 GtkWidget *rr_tree, *trr;
299 data_start = dptr = pd + offset;
301 len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
302 &name_len, &type, &class);
305 type_name = nbns_type_name(type);
306 class_name = dns_class_name(class);
311 data_len = pntohs(dptr);
315 case T_NB: /* "NB" record */
316 trr = add_item_to_tree(nbns_tree, offset,
317 (dptr - data_start) + data_len,
318 "%s: type %s, class %s",
319 name, type_name, class_name);
320 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
321 name_len, type_name, class_name, ttl, data_len);
322 offset += (dptr - data_start);
323 while (data_len > 0) {
325 /* WACK response. This doesn't contain the
326 * same type of RR data as other T_NB
329 add_item_to_tree(rr_tree, offset,
330 data_len, "(incomplete entry)");
333 flags = pntohs(dptr);
335 add_item_to_tree(rr_tree, offset, 2,
336 "Flags: 0x%x", flags);
341 add_item_to_tree(rr_tree, offset,
342 data_len, "(incomplete entry)");
345 flags = pntohs(dptr);
347 add_item_to_tree(rr_tree, offset, 2,
348 "Flags: 0x%x", flags);
353 add_item_to_tree(rr_tree, offset,
354 data_len, "(incomplete entry)");
357 add_item_to_tree(rr_tree, offset, 4,
359 ip_to_str((guint8 *)dptr));
367 case T_NBSTAT: /* "NBSTAT" record */
370 char nbname[16+4+1]; /* 4 for [<last char>] */
373 trr = add_item_to_tree(nbns_tree, offset,
374 (dptr - data_start) + data_len,
375 "%s: type %s, class %s",
376 name, type_name, class_name);
377 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
378 name_len, type_name, class_name, ttl, data_len);
379 offset += (dptr - data_start);
381 add_item_to_tree(rr_tree, offset,
382 data_len, "(incomplete entry)");
387 add_item_to_tree(rr_tree, offset, 2,
388 "Number of names: %u", num_names);
391 while (num_names != 0) {
393 add_item_to_tree(rr_tree, offset,
394 data_len, "(incomplete entry)");
397 memcpy(nbname, dptr, 16);
399 canonicalize_netbios_name(nbname);
400 add_item_to_tree(rr_tree, offset, 16,
406 add_item_to_tree(rr_tree, offset,
407 data_len, "(incomplete entry)");
410 name_flags = pntohs(dptr);
412 add_item_to_tree(rr_tree, offset, 2,
413 "Name flags: 0x%x", name_flags);
421 add_item_to_tree(rr_tree, offset,
422 data_len, "(incomplete entry)");
425 add_item_to_tree(rr_tree, offset, 6,
427 ether_to_str((guint8 *)dptr));
433 add_item_to_tree(rr_tree, offset,
434 data_len, "(incomplete entry)");
437 add_item_to_tree(rr_tree, offset, 1,
438 "Jumpers: 0x%x", *dptr);
444 add_item_to_tree(rr_tree, offset,
445 data_len, "(incomplete entry)");
448 add_item_to_tree(rr_tree, offset, 1,
449 "Test result: 0x%x", *dptr);
455 add_item_to_tree(rr_tree, offset,
456 data_len, "(incomplete entry)");
459 add_item_to_tree(rr_tree, offset, 2,
460 "Version number: 0x%x", pntohs(dptr));
466 add_item_to_tree(rr_tree, offset,
467 data_len, "(incomplete entry)");
470 add_item_to_tree(rr_tree, offset, 2,
471 "Period of statistics: 0x%x", pntohs(dptr));
477 add_item_to_tree(rr_tree, offset,
478 data_len, "(incomplete entry)");
481 add_item_to_tree(rr_tree, offset, 2,
482 "Number of CRCs: %u", pntohs(dptr));
488 add_item_to_tree(rr_tree, offset,
489 data_len, "(incomplete entry)");
492 add_item_to_tree(rr_tree, offset, 2,
493 "Number of alignment errors: %u", pntohs(dptr));
499 add_item_to_tree(rr_tree, offset,
500 data_len, "(incomplete entry)");
503 add_item_to_tree(rr_tree, offset, 2,
504 "Number of collisions: %u", pntohs(dptr));
510 add_item_to_tree(rr_tree, offset,
511 data_len, "(incomplete entry)");
514 add_item_to_tree(rr_tree, offset, 2,
515 "Number of send aborts: %u", pntohs(dptr));
521 add_item_to_tree(rr_tree, offset,
522 data_len, "(incomplete entry)");
525 add_item_to_tree(rr_tree, offset, 4,
526 "Number of good sends: %u", pntohl(dptr));
532 add_item_to_tree(rr_tree, offset,
533 data_len, "(incomplete entry)");
536 add_item_to_tree(rr_tree, offset, 4,
537 "Number of good receives: %u", pntohl(dptr));
543 add_item_to_tree(rr_tree, offset,
544 data_len, "(incomplete entry)");
547 add_item_to_tree(rr_tree, offset, 2,
548 "Number of retransmits: %u", pntohs(dptr));
554 add_item_to_tree(rr_tree, offset,
555 data_len, "(incomplete entry)");
558 add_item_to_tree(rr_tree, offset, 2,
559 "Number of no resource conditions: %u", pntohs(dptr));
565 add_item_to_tree(rr_tree, offset,
566 data_len, "(incomplete entry)");
569 add_item_to_tree(rr_tree, offset, 2,
570 "Number of command blocks: %u", pntohs(dptr));
576 add_item_to_tree(rr_tree, offset,
577 data_len, "(incomplete entry)");
580 add_item_to_tree(rr_tree, offset, 2,
581 "Number of pending sessions: %u", pntohs(dptr));
587 add_item_to_tree(rr_tree, offset,
588 data_len, "(incomplete entry)");
591 add_item_to_tree(rr_tree, offset, 2,
592 "Max number of pending sessions: %u", pntohs(dptr));
596 add_item_to_tree(rr_tree, offset, 2,
597 "Max total sessions possible: %u", pntohs(dptr));
603 add_item_to_tree(rr_tree, offset,
604 data_len, "(incomplete entry)");
607 add_item_to_tree(rr_tree, offset, 2,
608 "Session data packet size: %u", pntohs(dptr));
617 trr = add_item_to_tree(nbns_tree, offset,
618 (dptr - data_start) + data_len,
619 "%s: type %s, class %s",
620 name, type_name, class_name);
621 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
622 name_len, type_name, class_name, ttl, data_len);
623 offset += (dptr - data_start);
624 add_item_to_tree(rr_tree, offset, data_len, "Data");
629 return dptr - data_start;
633 dissect_query_records(const u_char *nbns_data_ptr, int count, const u_char *pd,
634 int cur_off, GtkWidget *nbns_tree)
637 GtkWidget *qatree, *ti;
639 qatree = gtk_tree_new();
643 cur_off += dissect_nbns_query(nbns_data_ptr, pd, cur_off, qatree);
644 ti = add_item_to_tree(GTK_WIDGET(nbns_tree),
645 start_off, cur_off - start_off, "Queries");
646 add_subtree(ti, qatree, ETT_NBNS_QRY);
648 return cur_off - start_off;
654 dissect_answer_records(const u_char *nbns_data_ptr, int count,
655 const u_char *pd, int cur_off, GtkWidget *nbns_tree, int opcode, char *name)
658 GtkWidget *qatree, *ti;
660 qatree = gtk_tree_new();
664 cur_off += dissect_nbns_answer(nbns_data_ptr, pd, cur_off,
666 ti = add_item_to_tree(GTK_WIDGET(nbns_tree), start_off, cur_off - start_off, name);
667 add_subtree(ti, qatree, ETT_NBNS_ANS);
669 return cur_off - start_off;
673 dissect_nbns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
675 GtkWidget *nbns_tree, *ti;
676 struct nbns_header header;
678 const u_char *nbns_data_ptr;
683 "Unknown operation (1)",
684 "Unknown operation (2)",
685 "Unknown operation (3)",
686 "Unknown operation (4)",
689 "Wait and Acknowledge",
692 "Unknown operation (10)",
693 "Unknown operation (11)",
694 "Unknown operation (12)",
695 "Unknown operation (13)",
696 "Unknown operation (14)",
697 "Multi-Homed Registration",
700 nbns_data_ptr = &pd[offset];
702 /* This is taken from samba/source/nmlib.c, parse_nmb() */
703 header.name_tran_id = pntohs(&pd[offset]);
704 header.opcode = (pd[offset+2] >> 3) & 0xf;
705 header.r = (pd[offset+2] >> 7) & 1;
707 nm_flags = ((pd[offset+2] & 0x7) << 4) + (pd[offset+3] >> 4);
708 header.nm_flags.bcast = (nm_flags & 1) ? 1 : 0;
709 header.nm_flags.recursion_available = (nm_flags & 8) ? 1 : 0;
710 header.nm_flags.recursion_desired = (nm_flags & 0x10) ? 1 : 0;
711 header.nm_flags.trunc = (nm_flags & 0x20) ? 1 : 0;
712 header.nm_flags.authoritative = (nm_flags & 0x40) ? 1 : 0;
714 header.rcode = pd[offset+3] & 0xf;
715 header.qdcount = pntohs(&pd[offset+4]);
716 header.ancount = pntohs(&pd[offset+6]);
717 header.nscount = pntohs(&pd[offset+8]);
718 header.arcount = pntohs(&pd[offset+10]);
720 if (check_col(fd, COL_PROTOCOL))
721 col_add_str(fd, COL_PROTOCOL, "NBNS (UDP)");
722 if (check_col(fd, COL_INFO)) {
723 if (header.opcode <= 15) {
724 col_add_fstr(fd, COL_INFO, "%s %s",
725 opcode[header.opcode], header.r ? "reply" : "request");
727 col_add_fstr(fd, COL_INFO, "Unknown operation (%d) %s",
728 header.opcode, header.r ? "reply" : "request");
733 ti = add_item_to_tree(GTK_WIDGET(tree), offset, END_OF_FRAME,
734 "NetBIOS Name Service");
735 nbns_tree = gtk_tree_new();
736 add_subtree(ti, nbns_tree, ETT_NBNS);
738 add_item_to_tree(nbns_tree, offset, 2, "Transaction ID: 0x%04X",
739 header.name_tran_id);
740 add_item_to_tree(nbns_tree, offset + 2, 1, "Type: %s",
741 header.r == 0 ? "Request" : "Response" );
743 if (header.opcode <= 15) {
744 add_item_to_tree(nbns_tree, offset + 2, 1, "Operation: %s (%d)",
745 opcode[header.opcode], header.opcode);
748 add_item_to_tree(nbns_tree, offset + 2, 1, "Operation: Unknown (%d)",
751 add_item_to_tree(nbns_tree, offset + 4, 2, "Questions: %d",
753 add_item_to_tree(nbns_tree, offset + 6, 2, "Answer RRs: %d",
755 add_item_to_tree(nbns_tree, offset + 8, 2, "Authority RRs: %d",
757 add_item_to_tree(nbns_tree, offset + 10, 2, "Additional RRs: %d",
760 cur_off = offset + 12;
762 if (header.qdcount > 0)
763 cur_off += dissect_query_records(nbns_data_ptr,
764 header.qdcount, pd, cur_off, nbns_tree);
766 if (header.ancount > 0)
767 cur_off += dissect_answer_records(nbns_data_ptr,
768 header.ancount, pd, cur_off, nbns_tree,
769 header.opcode, "Answers");
771 if (header.nscount > 0)
772 cur_off += dissect_answer_records(nbns_data_ptr,
773 header.nscount, pd, cur_off, nbns_tree,
775 "Authoritative nameservers");
777 if (header.arcount > 0)
778 cur_off += dissect_answer_records(nbns_data_ptr,
779 header.arcount, pd, cur_off, nbns_tree,
780 header.opcode, "Additional records");
786 dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
788 GtkWidget *nbdgm_tree, *ti;
789 struct nbdgm_header header;
795 "Direct_unique datagram",
796 "Direct_group datagram",
797 "Broadcast datagram",
799 "Datagram query request",
800 "Datagram positive query response",
801 "Datagram negative query response"
811 static value_string error_codes[] = {
812 { 0x82, "Destination name not present" },
813 { 0x83, "Invalid source name format" },
814 { 0x84, "Invalid destination name format" },
818 char *yesno[] = { "No", "Yes" };
821 int len, name_len, type, class;
823 header.msg_type = pd[offset];
825 flags = pd[offset+1];
826 header.flags.more = flags & 1;
827 header.flags.first = (flags & 2) >> 1;
828 header.flags.node_type = (flags & 12) >> 2;
830 header.dgm_id = pntohs(&pd[offset+2]);
831 memcpy(&header.src_ip, &pd[offset+4], 4);
832 header.src_port = pntohs(&pd[offset+8]);
834 if (header.msg_type == 0x10 ||
835 header.msg_type == 0x11 || header.msg_type == 0x12) {
836 header.dgm_length = pntohs(&pd[offset+10]);
837 header.pkt_offset = pntohs(&pd[offset+12]);
839 else if (header.msg_type == 0x13) {
840 header.error_code = pntohs(&pd[offset+10]);
843 message_index = header.msg_type - 0x0f;
844 if (message_index < 1 || message_index > 8) {
848 if (check_col(fd, COL_PROTOCOL))
849 col_add_str(fd, COL_PROTOCOL, "NetBIOS");
850 if (check_col(fd, COL_INFO)) {
851 col_add_fstr(fd, COL_INFO, "%s", message[message_index]);
855 ti = add_item_to_tree(GTK_WIDGET(tree), offset, header.dgm_length,
857 nbdgm_tree = gtk_tree_new();
858 add_subtree(ti, nbdgm_tree, ETT_NBDGM);
860 add_item_to_tree(nbdgm_tree, offset, 1, "Message Type: %s",
861 message[message_index]);
862 add_item_to_tree(nbdgm_tree, offset+1, 1, "More fragments follow: %s",
863 yesno[header.flags.more]);
864 add_item_to_tree(nbdgm_tree, offset+1, 1, "This is first fragment: %s",
865 yesno[header.flags.first]);
866 add_item_to_tree(nbdgm_tree, offset+1, 1, "Node Type: %s",
867 node[header.flags.node_type]);
869 add_item_to_tree(nbdgm_tree, offset+2, 2, "Datagram ID: 0x%04X",
871 add_item_to_tree(nbdgm_tree, offset+4, 4, "Source IP: %s",
872 ip_to_str((guint8 *)&header.src_ip));
873 add_item_to_tree(nbdgm_tree, offset+8, 2, "Source Port: %d",
878 if (header.msg_type == 0x10 ||
879 header.msg_type == 0x11 || header.msg_type == 0x12) {
881 add_item_to_tree(nbdgm_tree, offset, 2,
882 "Datagram length: %d bytes", header.dgm_length);
883 add_item_to_tree(nbdgm_tree, offset+2, 2,
884 "Packet offset: %d bytes", header.pkt_offset);
889 len = get_nbns_name_type_class(&pd[offset], pd, offset, name,
890 &name_len, &type, &class);
893 add_item_to_tree(nbdgm_tree, offset, len, "Source name: %s",
897 /* Destination name */
898 len = get_nbns_name_type_class(&pd[offset], pd, offset, name,
899 &name_len, &type, &class);
902 add_item_to_tree(nbdgm_tree, offset, len, "Destination name: %s",
906 /* here we can pass the packet off to the next protocol */
908 else if (header.msg_type == 0x13) {
909 add_item_to_tree(nbdgm_tree, offset, 1, "Error code: %s",
910 match_strval(header.error_code, error_codes));
913 /* Destination name */
914 len = get_nbns_name_type_class(&pd[offset], pd, offset, name,
915 &name_len, &type, &class);
918 add_item_to_tree(nbdgm_tree, offset, len, "Destination name: %s",