Tag NetBIOS Name Service-over-UDP packets as "NBNS (UDP)".
authorguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 14 Oct 1998 19:35:00 +0000 (19:35 +0000)
committerguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 14 Oct 1998 19:35:00 +0000 (19:35 +0000)
Give a detailed display of the innards of NBNS-over-UDP packets.  Export
some stuff from the DNS decoder for the use of the NBNS decoder (NBNS is
DNS-like).

Give a more detailed display of the innards of DNS packets as well.

Fix a couple of minor NBNS bugs.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@55 f5534014-38df-0310-8fa8-9805f1628bb7

ethereal.c
packet-dns.c
packet-nbns.c
packet.h

index d1707e0f55392701d17ffbb3f0f2dbf4a00cbf9b..9ad8af75ab724ee4fb0ca68c106e9f10a445dd69 100644 (file)
@@ -1,6 +1,6 @@
 /* ethereal.c
  *
- * $Id: ethereal.c,v 1.5 1998/10/12 01:40:47 gerald Exp $
+ * $Id: ethereal.c,v 1.6 1998/10/14 19:34:57 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -520,7 +520,7 @@ main(int argc, char *argv[])
   col_width = gdk_string_width(pl_style->font, "00:00:00:00:00:00") + 2;
   gtk_clist_set_column_width(GTK_CLIST(packet_list), COL_SOURCE, col_width);
   gtk_clist_set_column_width(GTK_CLIST(packet_list), COL_DESTINATION, col_width);
-  col_width = gdk_string_width(pl_style->font, "AppleTalk") + 2;
+  col_width = gdk_string_width(pl_style->font, "NBNS (UDP)") + 2;
   gtk_clist_set_column_width(GTK_CLIST(packet_list), COL_PROTOCOL, col_width);
   gtk_widget_set_usize(packet_list, -1, pl_size);
   gtk_paned_add1(GTK_PANED(u_pane), packet_list);
index 59f96a1beed00a3ca9207c4766e815269a851472..ad8e475617b54c8cf5280015992d569c217e9fb2 100644 (file)
@@ -1,7 +1,7 @@
 /* packet-dns.c
  * Routines for DNS packet disassembly
  *
- * $Id: packet-dns.c,v 1.4 1998/09/27 22:12:28 gerald Exp $
+ * $Id: packet-dns.c,v 1.5 1998/10/14 19:34:58 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -43,6 +43,7 @@
 
 #include "ethereal.h"
 #include "packet.h"
+#include "packet-dns.h"
 
 
 /* DNS structs and definitions */
@@ -56,8 +57,6 @@ typedef struct _e_dns {
   guint16 dns_add;
 } e_dns;
 
-#define MAXDNAME        1025            /* maximum domain name */
-
 /* type values  */
 #define T_A             1               /* host address */
 #define T_NS            2               /* authoritative server */
@@ -71,8 +70,6 @@ typedef struct _e_dns {
 #define T_AAAA          28              /* IP6 Address */
 
 
-static const u_char *dns_data_ptr;
-
 static char *
 dns_type_name (int type)
 {
@@ -116,7 +113,7 @@ dns_type_name (int type)
 }
 
 
-static char *
+char *
 dns_class_name(int class)
 {
   char *class_name;
@@ -171,7 +168,8 @@ copy_one_name_component(const u_char *dataptr, char *nameptr)
 
 
 static int
-copy_name_component_rec(const u_char *dataptr, char *nameptr, int *real_string_len)
+copy_name_component_rec(const u_char *dns_data_ptr, const u_char *dataptr,
+  char *nameptr, int *real_string_len)
 {
   int len = 0;
   int str_len;
@@ -182,7 +180,7 @@ copy_name_component_rec(const u_char *dataptr, char *nameptr, int *real_string_l
     compress = 1;
     offset = get_compressed_name_offset(dataptr);
     dataptr = dns_data_ptr + offset;
-    copy_name_component_rec(dataptr, nameptr, &str_len);
+    copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
     *real_string_len += str_len;
     nameptr += str_len;
     len = 2;
@@ -202,7 +200,7 @@ copy_name_component_rec(const u_char *dataptr, char *nameptr, int *real_string_l
 
   if (*dataptr > 0) {
     *nameptr++ = '.';
-    len += copy_name_component_rec(dataptr, nameptr, &str_len);
+    len += copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
     *real_string_len += str_len;
     return len;
   }
@@ -211,24 +209,27 @@ copy_name_component_rec(const u_char *dataptr, char *nameptr, int *real_string_l
 }
 
 
-static int
-get_dns_name(const u_char *pd, int offset, char *nameptr, int maxname)
+int
+get_dns_name(const u_char *dns_data_ptr, const u_char *pd, int offset,
+  char *nameptr, int maxname)
 {
   int len;
   const u_char *dataptr = pd + offset;
   int str_len = 0;
 
   memset (nameptr, 0, maxname);
-  len = copy_name_component_rec(dataptr, nameptr, &str_len);
+  len = copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
   
   return len;
 }
 
 
 static int
-get_dns_name_type_class (const u_char *pd,
+get_dns_name_type_class (const u_char *dns_data_ptr,
+                        const u_char *pd,
                         int offset,
-                        char *name_ret, 
+                        char *name_ret,
+                        int *name_len_ret,
                         int *type_ret,
                         int *class_ret)
 {
@@ -239,19 +240,20 @@ get_dns_name_type_class (const u_char *pd,
   char name[MAXDNAME];
   const u_char *pd_save;
 
-  name_len = get_dns_name(pd, offset, name, sizeof(name));
+  name_len = get_dns_name(dns_data_ptr, pd, offset, name, sizeof(name));
   pd += offset;
   pd_save = pd;
   pd += name_len;
   
-  type = (*pd << 8) | *(pd + 1);
+  type = pntohs(pd);
   pd += 2;
-  class = (*pd << 8) | *(pd + 1);
+  class = pntohs(pd);
   pd += 2;
 
   strcpy (name_ret, name);
   *type_ret = type;
   *class_ret = class;
+  *name_len_ret = name_len;
 
   len = pd - pd_save;
   return len;
@@ -259,135 +261,183 @@ get_dns_name_type_class (const u_char *pd,
 
 
 static int
-dissect_dns_query(const u_char *pd, int offset, GtkWidget *dns_tree)
+dissect_dns_query(const u_char *dns_data_ptr, const u_char *pd, int offset,
+  GtkWidget *dns_tree)
 {
   int len;
   char name[MAXDNAME];
+  int name_len;
   int type;
   int class;
   char *class_name;
   char *type_name;
+  const u_char *dptr;
+  const u_char *data_start;
 
-  len = get_dns_name_type_class (pd, offset, name, &type, &class);
+  data_start = dptr = pd + offset;
+
+  len = get_dns_name_type_class(dns_data_ptr, pd, offset, name, &name_len,
+    &type, &class);
+  dptr += len;
+
+  add_item_to_tree(dns_tree, offset, name_len, "Name: %s", name);
+  offset += name_len;
 
   type_name = dns_type_name(type);
+  add_item_to_tree(dns_tree, offset, 2, "Type: %s", type_name);
+  offset += 2;
+
   class_name = dns_class_name(class);
+  add_item_to_tree(dns_tree, offset, 2, "Class: %s", class_name);
+  offset += 2;
   
-  add_item_to_tree(dns_tree, offset, len, "%s: type %s, class %s", 
-                  name, type_name, class_name );
-  
-  return len;
+  return dptr - data_start;
 }
 
 
+GtkWidget *
+add_rr_to_tree(GtkWidget *trr, int rr_type, int offset, const char *name,
+  int namelen, const char *type_name, const char *class_name, u_int ttl,
+  u_short data_len)
+{
+  GtkWidget *rr_tree;
+
+  rr_tree = gtk_tree_new();
+  add_subtree(trr, rr_tree, rr_type);
+  add_item_to_tree(rr_tree, offset, namelen, "Name: %s", name);
+  offset += namelen;
+  add_item_to_tree(rr_tree, offset, 2, "Type: %s", type_name);
+  offset += 2;
+  add_item_to_tree(rr_tree, offset, 2, "Class: %s", class_name);
+  offset += 2;
+  add_item_to_tree(rr_tree, offset, 4, "Time to live: %u", ttl);
+  offset += 4;
+  add_item_to_tree(rr_tree, offset, 2, "Data length: %u", data_len);
+  return rr_tree;
+}
+
 static int
-dissect_dns_answer(const u_char *pd, int offset, GtkWidget *dns_tree)
+dissect_dns_answer(const u_char *dns_data_ptr, const u_char *pd, int offset,
+  GtkWidget *dns_tree)
 {
   int len;
   char name[MAXDNAME];
+  int name_len;
   int type;
   int class;
   char *class_name;
   char *type_name;
   const u_char *dptr;
   const u_char *data_start;
-  const u_char *res_ptr;
   u_int ttl;
   u_short data_len;
+  GtkWidget *rr_tree, *trr;
 
   data_start = dptr = pd + offset;
 
-  len = get_dns_name_type_class (pd, offset, name, &type, &class);
+  len = get_dns_name_type_class(dns_data_ptr, pd, offset, name, &name_len,
+    &type, &class);
   dptr += len;
 
-  /* this works regardless of the alignment  */
-  ttl = (*dptr << 24) | *(dptr + 1) << 16 | *(dptr + 2) << 8 | *(dptr + 3);
-  dptr += 4;
-  data_len = (*dptr << 8) | *(dptr + 1);
-  dptr += 2;
-
   type_name = dns_type_name(type);
   class_name = dns_class_name(class);
-  res_ptr = dptr;
 
-  /* skip the resource data  */
-  dptr += data_len;
-  
-  len = dptr - data_start;
-  
+  ttl = pntohl(dptr);
+  dptr += 4;
+
+  data_len = pntohs(dptr);
+  dptr += 2;
+
   switch (type) {
   case T_A:            /* "A" record */
-    add_item_to_tree(dns_tree, offset, len, 
+    trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
                     "%s: type %s, class %s, addr %d.%d.%d.%d",
                     name, type_name, class_name,
-                    *res_ptr, *(res_ptr+1), *(res_ptr+2), *(res_ptr+3));
+                    *dptr, *(dptr+1), *(dptr+2), *(dptr+3));
+    rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len, type_name,
+                     class_name, ttl, data_len);
+    offset += (dptr - data_start);
+    add_item_to_tree(rr_tree, offset, 4, "Addr: %d.%d.%d.%d",
+                    *dptr, *(dptr+1), *(dptr+2), *(dptr+3));
     break;
 
   case T_NS:           /* "NS" record */
     {
       char ns_name[MAXDNAME];
+      int ns_name_len;
       
-      get_dns_name(res_ptr, 0, ns_name, sizeof(ns_name));
-      add_item_to_tree(dns_tree, offset, len, 
-                      "%s: %s, type %s, class %s",
-                      name, ns_name, type_name, class_name);
-      
+      ns_name_len = get_dns_name(dns_data_ptr, dptr, 0, ns_name, sizeof(ns_name));
+      trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
+                      "%s: type %s, class %s, ns %s",
+                      name, type_name, class_name, ns_name);
+      rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
+                       type_name, class_name, ttl, data_len);
+      offset += (dptr - data_start);
+      add_item_to_tree(rr_tree, offset, ns_name_len, "Name server: %s", ns_name);
     }
     break;
 
     /* TODO: parse more record types */
       
-    default:
-    add_item_to_tree(dns_tree, offset, len, "%s: type %s, class %s", 
+  default:
+    trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
+                     "%s: type %s, class %s",
                     name, type_name, class_name);
+    rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len, type_name,
+                       class_name, ttl, data_len);
+    offset += (dptr - data_start);
+    add_item_to_tree(rr_tree, offset, data_len, "Data");
   }
   
-  return len;
+  dptr += data_len;
+       
+  return dptr - data_start;
 }
 
-
 static int
-dissect_answer_records(int count, const u_char *pd, int cur_off
-                      GtkWidget *dns_tree, char *name)
+dissect_query_records(const u_char *dns_data_ptr, int count, const u_char *pd
+                     int cur_off, GtkWidget *dns_tree)
 {
   int start_off;
   GtkWidget *qatree, *ti;
   
   qatree = gtk_tree_new();
   start_off = cur_off;
-
+  
   while (count-- > 0)
-    cur_off += dissect_dns_answer(pd, cur_off, qatree);
-  ti = add_item_to_tree(GTK_WIDGET(dns_tree), start_off, cur_off - start_off, name);
-  add_subtree(ti, qatree, ETT_DNS_ANS);
+    cur_off += dissect_dns_query(dns_data_ptr, pd, cur_off, qatree);
+  ti = add_item_to_tree(GTK_WIDGET(dns_tree), 
+                       start_off, cur_off - start_off, "Queries");
+  add_subtree(ti, qatree, ETT_DNS_QRY);
 
   return cur_off - start_off;
 }
 
 
+
 static int
-dissect_query_records(int count, const u_char *pd, 
-                     int cur_off, GtkWidget *dns_tree)
+dissect_answer_records(const u_char *dns_data_ptr, int count,
+                       const u_char *pd, int cur_off, GtkWidget *dns_tree,
+                       char *name)
 {
   int start_off;
   GtkWidget *qatree, *ti;
   
   qatree = gtk_tree_new();
   start_off = cur_off;
-  
+
   while (count-- > 0)
-    cur_off += dissect_dns_query(pd, cur_off, qatree);
-  ti = add_item_to_tree(GTK_WIDGET(dns_tree), 
-                       start_off, cur_off - start_off, "Queries");
-  add_subtree(ti, qatree, ETT_DNS_QRY);
+    cur_off += dissect_dns_answer(dns_data_ptr, pd, cur_off, qatree);
+  ti = add_item_to_tree(GTK_WIDGET(dns_tree), start_off, cur_off - start_off, name);
+  add_subtree(ti, qatree, ETT_DNS_ANS);
 
   return cur_off - start_off;
 }
 
 
-
 void
 dissect_dns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
+  const u_char *dns_data_ptr;
   e_dns     *dh;
   GtkWidget *dns_tree, *ti;
   guint16    id, flags, quest, ans, auth, add;
@@ -430,17 +480,19 @@ dissect_dns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
     cur_off = offset + 12;
     
     if (quest > 0)
-      cur_off += dissect_query_records(quest, pd, cur_off, dns_tree);
+      cur_off += dissect_query_records(dns_data_ptr, quest, pd, cur_off,
+                                       dns_tree);
     
     if (ans > 0)
-      cur_off += dissect_answer_records(ans, pd, cur_off, dns_tree, "Answers");
+      cur_off += dissect_answer_records(dns_data_ptr, ans, pd, cur_off,
+          dns_tree, "Answers");
     
     if (auth > 0)
-      cur_off += dissect_answer_records(auth, pd, cur_off, dns_tree, 
-                                       "Authoritative nameservers");
+      cur_off += dissect_answer_records(dns_data_ptr, auth, pd, cur_off,
+          dns_tree, "Authoritative nameservers");
 
     if (add > 0)
-      cur_off += dissect_answer_records(add, pd, cur_off, dns_tree, 
-                                       "Additional records");
+      cur_off += dissect_answer_records(dns_data_ptr, add, pd, cur_off,
+          dns_tree, "Additional records");
   }
 }
index 3a69973f082d63ae5dddf73df065779ab26191a7..90dbda7ee3db5b72c5145ef67544206f2e1b30a5 100644 (file)
@@ -1,8 +1,9 @@
 /* packet-nbns.c
  * Routines for NetBIOS Name Service packet disassembly
  * Gilbert Ramirez <gram@verdict.uthscsa.edu>
+ * Much stuff added by Guy Harris <guy@netapp.com>
  *
- * $Id: packet-nbns.c,v 1.1 1998/10/14 04:09:11 gram Exp $
+ * $Id: packet-nbns.c,v 1.2 1998/10/14 19:34:59 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -44,6 +45,7 @@
 
 #include "ethereal.h"
 #include "packet.h"
+#include "packet-dns.h"
 
 /* Packet structure taken from RFC 1002. See also RFC 1001.
  * The Samba source code, specifically nmblib.c, also helps a lot. */
@@ -67,36 +69,638 @@ struct nbns_header {
        guint16         arcount;
 };
 
+/* type values  */
+#define T_NB            32              /* NetBIOS name service RR */
+#define T_NBSTAT        33              /* NetBIOS node status RR */
+
+
+static char *
+nbns_type_name (int type)
+{
+       switch (type) {
+       case T_NB:
+               return "NB";
+       case T_NBSTAT:
+               return "NBSTAT";
+       }
+       
+       return "unknown";
+}
+
+/* "Canonicalize" a 16-character NetBIOS name by:
+ *
+ *     removing and saving the last byte;
+ *
+ *     stripping trailing blanks;
+ *
+ *     appending the trailing byte, as a hex number, in square brackets. */
+static char *
+canonicalize_netbios_name(char *nbname)
+{
+       char *pnbname;
+       u_char lastchar;
+
+       /* Get the last character of the name, as it's a special number
+        * indicating the type of the name, rather than part of the name
+        * *per se*. */
+       pnbname = nbname + 15;  /* point to the 16th character */
+       lastchar = *(unsigned char *)pnbname;
+
+       /* Now strip off any trailing blanks used to pad it to
+        * 16 bytes. */
+       while (pnbname > &nbname[0]) {
+               if (*(pnbname - 1) != ' ')
+                       break;          /* found non-blank character */
+               pnbname--;              /* blank - skip over it */
+       }
+
+       /* Replace the last character with its hex value, in square
+        * brackets, to make it easier to tell what it is. */
+       sprintf(pnbname, "[%02X]", lastchar);
+       pnbname += 4;
+       return pnbname;
+}
+
+static int
+get_nbns_name_type_class(const u_char *nbns_data_ptr, const u_char *pd,
+    int offset, char *name_ret, int *name_len_ret, int *type_ret,
+    int *class_ret)
+{
+       int len;
+       int name_len;
+       int type;
+       int class;
+       char name[MAXDNAME];
+       char nbname[MAXDNAME+4];        /* 4 for [<last char>] */
+       char *pname, *pnbname, cname, cnbname;
+       const u_char *pd_save;
+
+       name_len = get_dns_name(nbns_data_ptr, pd, offset, name, sizeof(name));
+       pd += offset;
+       pd_save = pd;
+       pd += name_len;
+       
+       type = pntohs(pd);
+       pd += 2;
+       class = pntohs(pd);
+       pd += 2;
+
+       /* OK, now undo the first-level encoding. */
+       pname = &name[0];
+       pnbname = &nbname[0];
+       for (;;) {
+               /* Every two characters of the first level-encoded name
+                * turn into one character in the decoded name. */
+               cname = *pname;
+               if (cname == '\0')
+                       break;          /* no more characters */
+               if (cname == '.')
+                       break;          /* scope ID follows */
+               if (cname < 'A' || cname > 'Z') {
+                       /* Not legal. */
+                       strcpy(nbname,
+                           "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
+                       goto bad;
+               }
+               cname -= 'A';
+               cnbname = cname << 4;
+               pname++;
+
+               cname = *pname;
+               if (cname == '\0' || cname == '.') {
+                       /* No more characters in the name - but we're in
+                        * the middle of a pair.  Not legal. */
+                       strcpy(nbname,
+                           "Illegal NetBIOS name (odd number of bytes)");
+                       goto bad;
+               }
+               if (cname < 'A' || cname > 'Z') {
+                       /* Not legal. */
+                       strcpy(nbname,
+                           "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
+                       goto bad;
+               }
+               cname -= 'A';
+               cnbname |= cname;
+               pname++;
+
+               /* Store the character. */
+               *pnbname++ = cnbname;
+       }
+
+       /* NetBIOS names are supposed to be exactly 16 bytes long. */
+       if (pnbname - nbname == 16) {
+               /* This one is; canonicalize its name. */
+               pnbname = canonicalize_netbios_name(nbname);
+       } else {
+               sprintf(nbname, "Illegal NetBIOS name (%d bytes long)",
+                   pnbname - nbname);
+               goto bad;
+       }
+       if (cname == '.') {
+               /* We have a scope ID, starting at "pname"; append that to
+                * the decoded host name. */
+               strcpy(pnbname, pname);
+       } else {
+               /* Terminate the decoded host name. */
+               *pnbname = '\0';
+       }
+
+bad:
+       strcpy (name_ret, nbname);
+       *type_ret = type;
+       *class_ret = class;
+       *name_len_ret = name_len;
+
+       len = pd - pd_save;
+       return len;
+}
+
+
+static int
+dissect_nbns_query(const u_char *nbns_data_ptr, const u_char *pd, int offset,
+    GtkWidget *nbns_tree)
+{
+       int len;
+       char name[MAXDNAME];
+       int name_len;
+       int type;
+       int class;
+       char *class_name;
+       char *type_name;
+       const u_char *dptr;
+       const u_char *data_start;
+
+       data_start = dptr = pd + offset;
+
+       len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
+           &name_len, &type, &class);
+       dptr += len;
+
+       add_item_to_tree(nbns_tree, offset, name_len, "Name: %s", name);
+       offset += name_len;
+
+       type_name = nbns_type_name(type);
+       add_item_to_tree(nbns_tree, offset, 2, "Type: %s", type_name);
+       offset += 2;
+
+       class_name = dns_class_name(class);
+       add_item_to_tree(nbns_tree, offset, 2, "Class: %s", class_name);
+       offset += 2;
+       
+       return dptr - data_start;
+}
+
+
+static int
+dissect_nbns_answer(const u_char *nbns_data_ptr, const u_char *pd, int offset,
+    GtkWidget *nbns_tree, int opcode)
+{
+       int len;
+       char name[MAXDNAME];
+       int name_len;
+       int type;
+       int class;
+       char *class_name;
+       char *type_name;
+       const u_char *dptr;
+       const u_char *data_start;
+       u_int ttl;
+       u_short data_len;
+       u_short flags;
+       GtkWidget *rr_tree, *trr;
+
+       data_start = dptr = pd + offset;
+
+       len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
+           &name_len, &type, &class);
+       dptr += len;
+
+       type_name = nbns_type_name(type);
+       class_name = dns_class_name(class);
+
+       ttl = pntohl(dptr);
+       dptr += 4;
+
+       data_len = pntohs(dptr);
+       dptr += 2;
+
+       switch (type) {
+       case T_NB:              /* "NB" record */
+               trr = add_item_to_tree(nbns_tree, offset,
+                   (dptr - data_start) + data_len,
+                   "%s: type %s, class %s",
+                   name, type_name, class_name);
+               rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
+                   name_len, type_name, class_name, ttl, data_len);
+               offset += (dptr - data_start);
+               while (data_len > 0) {
+                       if (opcode == 0x7) {
+                               /* WACK response.  This doesn't contain the
+                                * same type of RR data as other T_NB
+                                * responses.  */
+                               if (data_len < 2) {
+                                       add_item_to_tree(rr_tree, offset,
+                                           data_len, "(incomplete entry)");
+                                       break;
+                               }
+                               flags = pntohs(dptr);
+                               dptr += 2;
+                               add_item_to_tree(rr_tree, offset, 2,
+                                   "Flags: 0x%x", flags);
+                               offset += 2;
+                               data_len -= 2;
+                       } else {
+                               if (data_len < 2) {
+                                       add_item_to_tree(rr_tree, offset,
+                                           data_len, "(incomplete entry)");
+                                       break;
+                               }
+                               flags = pntohs(dptr);
+                               dptr += 2;
+                               add_item_to_tree(rr_tree, offset, 2,
+                                   "Flags: 0x%x", flags);
+                               offset += 2;
+                               data_len -= 2;
+
+                               if (data_len < 4) {
+                                       add_item_to_tree(rr_tree, offset,
+                                           data_len, "(incomplete entry)");
+                                       break;
+                               }
+                               add_item_to_tree(rr_tree, offset, 4,
+                                   "Addr: %d.%d.%d.%d",
+                                   *dptr, *(dptr+1), *(dptr+2), *(dptr+3));
+                               dptr += 4;
+                               offset += 4;
+                               data_len -= 4;
+                       }
+               }
+               break;
+
+       case T_NBSTAT:  /* "NBSTAT" record */
+               {
+                       u_int num_names;
+                       char nbname[16+4+1];    /* 4 for [<last char>] */
+                       u_short name_flags;
+                       
+                       trr = add_item_to_tree(nbns_tree, offset,
+                           (dptr - data_start) + data_len,
+                           "%s: type %s, class %s",
+                           name, type_name, class_name);
+                       rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
+                           name_len, type_name, class_name, ttl, data_len);
+                       offset += (dptr - data_start);
+                       if (data_len < 1) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       num_names = *dptr;
+                       dptr += 1;
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Number of names: %u", num_names);
+                       offset += 1;
+
+                       while (num_names != 0) {
+                               if (data_len < 16) {
+                                       add_item_to_tree(rr_tree, offset,
+                                           data_len, "(incomplete entry)");
+                                       goto out;
+                               }
+                               memcpy(nbname, dptr, 16);
+                               dptr += 16;
+                               canonicalize_netbios_name(nbname);
+                               add_item_to_tree(rr_tree, offset, 16,
+                                   "Name: %s", nbname);
+                               offset += 16;
+                               data_len -= 16;
+
+                               if (data_len < 2) {
+                                       add_item_to_tree(rr_tree, offset,
+                                           data_len, "(incomplete entry)");
+                                       goto out;
+                               }
+                               name_flags = pntohs(dptr);
+                               dptr += 2;
+                               add_item_to_tree(rr_tree, offset, 2,
+                                   "Name flags: 0x%x", name_flags);
+                               offset += 2;
+                               data_len -= 2;
+
+                               num_names--;
+                       }
+
+                       if (data_len < 6) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 6,
+                           "Unit ID: %02x:%02x:%02x:%02x:%02x:%02x",
+                           *dptr, *(dptr + 1), *(dptr + 2),
+                           *(dptr + 3), *(dptr + 4), *(dptr + 5));
+                       dptr += 6;
+                       offset += 6;
+                       data_len -= 6;
+
+                       if (data_len < 1) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 1,
+                           "Jumpers: 0x%x", *dptr);
+                       dptr += 1;
+                       offset += 1;
+                       data_len -= 1;
+
+                       if (data_len < 1) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 1,
+                           "Test result: 0x%x", *dptr);
+                       dptr += 1;
+                       offset += 1;
+                       data_len -= 1;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Version number: 0x%x", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Period of statistics: 0x%x", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Number of CRCs: %u", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Number of alignment errors: %u", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Number of collisions: %u", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Number of send aborts: %u", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+
+                       if (data_len < 4) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 4,
+                           "Number of good sends: %u", pntohl(dptr));
+                       dptr += 4;
+                       offset += 4;
+                       data_len -= 4;
+
+                       if (data_len < 4) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 4,
+                           "Number of good receives: %u", pntohl(dptr));
+                       dptr += 4;
+                       offset += 4;
+                       data_len -= 4;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Number of retransmits: %u", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Number of no resource conditions: %u", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Number of command blocks: %u", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Number of pending sessions: %u", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Max number of pending sessions: %u", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Max total sessions possible: %u", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+
+                       if (data_len < 2) {
+                               add_item_to_tree(rr_tree, offset,
+                                   data_len, "(incomplete entry)");
+                               break;
+                       }
+                       add_item_to_tree(rr_tree, offset, 2,
+                           "Session data packet size: %u", pntohs(dptr));
+                       dptr += 2;
+                       offset += 2;
+                       data_len -= 2;
+               }
+       out:
+               break;
+
+       default:
+               trr = add_item_to_tree(nbns_tree, offset,
+                   (dptr - data_start) + data_len,
+                    "%s: type %s, class %s",
+                   name, type_name, class_name);
+               rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
+                   name_len, type_name, class_name, ttl, data_len);
+               offset += (dptr - data_start);
+               add_item_to_tree(rr_tree, offset, data_len, "Data");
+               break;
+       }
+       dptr += data_len;
+       
+       return dptr - data_start;
+}
+
+static int
+dissect_query_records(const u_char *nbns_data_ptr, int count, const u_char *pd, 
+    int cur_off, GtkWidget *nbns_tree)
+{
+       int start_off;
+       GtkWidget *qatree, *ti;
+       
+       qatree = gtk_tree_new();
+       start_off = cur_off;
+       
+       while (count-- > 0)
+               cur_off += dissect_nbns_query(nbns_data_ptr, pd, cur_off, qatree);
+       ti = add_item_to_tree(GTK_WIDGET(nbns_tree), 
+                       start_off, cur_off - start_off, "Queries");
+       add_subtree(ti, qatree, ETT_NBNS_QRY);
+
+       return cur_off - start_off;
+}
+
+
+
+static int
+dissect_answer_records(const u_char *nbns_data_ptr, int count,
+    const u_char *pd, int cur_off, GtkWidget *nbns_tree, int opcode, char *name)
+{
+       int start_off;
+       GtkWidget *qatree, *ti;
+       
+       qatree = gtk_tree_new();
+       start_off = cur_off;
+
+       while (count-- > 0)
+               cur_off += dissect_nbns_answer(nbns_data_ptr, pd, cur_off,
+                                       qatree, opcode);
+       ti = add_item_to_tree(GTK_WIDGET(nbns_tree), start_off, cur_off - start_off, name);
+       add_subtree(ti, qatree, ETT_NBNS_ANS);
+
+       return cur_off - start_off;
+}
+
 void
 dissect_nbns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
 {
-       GtkWidget                       *nbns_tree, *ti;
+       GtkWidget               *nbns_tree, *ti;
        struct nbns_header      header;
-       int                                     nm_flags;
+       int                     nm_flags;
+       const u_char            *nbns_data_ptr;
+       int                     cur_off;
 
        char *opcode[] = {
                "Query",
-               "Unknown",
-               "Unknown",
-               "Unknown",
-               "Unknown",
+               "Unknown operation (1)",
+               "Unknown operation (2)",
+               "Unknown operation (3)",
+               "Unknown operation (4)",
                "Registration",
                "Release",
                "Wait and Acknowledge",
-               "Refresh"
-               "Refresh(altcode)"
-               "Unknown",
-               "Unknown",
-               "Unknown",
-               "Unknown",
-               "Unknown",
+               "Refresh",
+               "Refresh(altcode)",
+               "Unknown operation (10)",
+               "Unknown operation (11)",
+               "Unknown operation (12)",
+               "Unknown operation (13)",
+               "Unknown operation (14)",
                "Multi-Homed Registration",
        };
 
+       nbns_data_ptr = &pd[offset];
+
+       /* This is taken from samba/source/nmlib.c, parse_nmb() */
+       header.name_tran_id = pntohs(&pd[offset]);
+       header.opcode = (pd[offset+2] >> 3) & 0xf;
+       header.r = (pd[offset+2] >> 7) & 1;
+
+       nm_flags = ((pd[offset+2] & 0x7) << 4) + (pd[offset+3] >> 4);
+       header.nm_flags.bcast = (nm_flags & 1) ? 1 : 0;
+       header.nm_flags.recursion_available = (nm_flags & 8) ? 1 : 0;
+       header.nm_flags.recursion_desired = (nm_flags & 0x10) ? 1 : 0;
+       header.nm_flags.trunc = (nm_flags & 0x20) ? 1 : 0;
+       header.nm_flags.authoritative = (nm_flags & 0x40) ? 1 : 0;
+
+       header.rcode = pd[offset+3] & 0xf;
+       header.qdcount = pntohs(&pd[offset+4]);
+       header.ancount = pntohs(&pd[offset+6]);
+       header.nscount = pntohs(&pd[offset+8]);
+       header.arcount = pntohs(&pd[offset+10]);
+
        if (fd->win_info[COL_NUM]) {
-                       /*strcpy(fd->win_info[COL_PROTOCOL], "NBNS (UDP)");*/
-                       strcpy(fd->win_info[COL_PROTOCOL], "NBNS");
-                       strcpy(fd->win_info[COL_INFO], "NetBIOS Name Service");
+               strcpy(fd->win_info[COL_PROTOCOL], "NBNS (UDP)");
+               if (header.opcode <= 15) {
+                       sprintf(fd->win_info[COL_INFO], "%s %s",
+                           opcode[header.opcode], header.r ? "reply" : "request");
+               } else {
+                       sprintf(fd->win_info[COL_INFO], "Unknown operation (%d) %s",
+                           header.opcode, header.r ? "reply" : "request");
+               }
        }
 
        if (tree) {
@@ -105,27 +709,9 @@ dissect_nbns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
                nbns_tree = gtk_tree_new();
                add_subtree(ti, nbns_tree, ETT_NBNS);
 
-               /* This is taken from samba/source/nmlib.c, parse_nmb() */
-               header.name_tran_id = pntohs(&pd[offset]);
-               header.opcode = (pd[offset+2] >> 3) & 0xf;
-               header.r = (pd[offset+2] >> 7) & 1;
-
-               nm_flags = ((pd[offset+2] & 0x7) << 4) + (pd[offset+3] >> 4);
-               header.nm_flags.bcast = (nm_flags & 1) ? 1 : 0;
-               header.nm_flags.recursion_available = (nm_flags & 8) ? 1 : 0;
-               header.nm_flags.recursion_desired = (nm_flags & 0x10) ? 1 : 0;
-               header.nm_flags.trunc = (nm_flags & 0x20) ? 1 : 0;
-               header.nm_flags.authoritative = (nm_flags & 0x40) ? 1 : 0;
-
-               header.rcode = pd[offset+3] & 0xf;
-               header.qdcount = pletohs(&pd[offset+4]);
-               header.ancount = pletohs(&pd[offset+6]);
-               header.nscount = pletohs(&pd[offset+8]);
-               header.arcount = pletohs(&pd[offset+10]);
-
-               add_item_to_tree(nbns_tree, offset,             2, "Transaction ID: 0x%04X",
+               add_item_to_tree(nbns_tree, offset,      2, "Transaction ID: 0x%04X",
                                header.name_tran_id);
-               add_item_to_tree(nbns_tree, offset + 2, 1,      "Type: %s",
+               add_item_to_tree(nbns_tree, offset +  2, 1, "Type: %s",
                                header.r == 0 ? "Request" : "Response" );
                
                if (header.opcode <= 15) {
@@ -136,22 +722,35 @@ dissect_nbns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
                        add_item_to_tree(nbns_tree, offset + 2, 1, "Operation: Unknown (%d)",
                                        header.opcode);
                }
-
-/*             add_item_to_tree(nbns_tree, offset+2,   2, */
+               add_item_to_tree(nbns_tree, offset +  4, 2, "Questions: %d",
+                                       header.qdcount);
+               add_item_to_tree(nbns_tree, offset +  6, 2, "Answer RRs: %d",
+                                       header.ancount);
+               add_item_to_tree(nbns_tree, offset +  8, 2, "Authority RRs: %d",
+                                       header.nscount);
+               add_item_to_tree(nbns_tree, offset + 10, 2, "Additional RRs: %d",
+                                       header.arcount);
+
+               cur_off = offset + 12;
+    
+               if (header.qdcount > 0)
+                       cur_off += dissect_query_records(nbns_data_ptr,
+                                       header.qdcount, pd, cur_off, nbns_tree);
+
+               if (header.ancount > 0)
+                       cur_off += dissect_answer_records(nbns_data_ptr,
+                                       header.ancount, pd, cur_off, nbns_tree,
+                                       header.opcode, "Answers");
+
+               if (header.nscount > 0)
+                       cur_off += dissect_answer_records(nbns_data_ptr,
+                                       header.nscount, pd, cur_off, nbns_tree, 
+                                       header.opcode,
+                                       "Authoritative nameservers");
+
+               if (header.arcount > 0)
+                       cur_off += dissect_answer_records(nbns_data_ptr,
+                                       header.arcount, pd, cur_off, nbns_tree, 
+                                       header.opcode, "Additional records");
        }
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
index 90f12013a57ac69f7345cec9d6eecf6fb6e88bf0..2d02f374de6368fc4145d0c457a6e4f82adbc6ec 100644 (file)
--- a/packet.h
+++ b/packet.h
@@ -1,7 +1,7 @@
 /* packet.h
  * Definitions for packet disassembly structures and routines
  *
- * $Id: packet.h,v 1.16 1998/10/14 05:18:32 gram Exp $
+ * $Id: packet.h,v 1.17 1998/10/14 19:35:00 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -405,6 +405,7 @@ enum {
        ETT_DNS,
        ETT_DNS_ANS,
        ETT_DNS_QRY,
+       ETT_DNS_RR,
        ETT_RIP,
        ETT_RIP_VEC,
        ETT_OSPF,
@@ -427,6 +428,9 @@ enum {
        ETT_IPXSAP,
        ETT_IPXSAP_SERVER,
        ETT_NBNS,
+       ETT_NBNS_ANS,
+       ETT_NBNS_QRY,
+       ETT_NBNS_RR,
        ETT_NBIPX,
        NUM_TREE_TYPES  /* last item number plus one */
 };