Make the "Save only marked frames" button in the "Save As..." dialog box
[obnox/wireshark/wip.git] / packet-nbns.c
index 15a2c1116c8a40a9c0236f41c8038025b5fefef4..b64d3bc3cc674a4f34d4873ad8dad4dd7bf581bc 100644 (file)
@@ -1,10 +1,9 @@
 /* packet-nbns.c
  * Routines for NetBIOS-over-TCP packet disassembly (the name dates back
  * to when it had only NBNS)
- * Gilbert Ramirez <gram@xiexie.org>
- * Much stuff added by Guy Harris <guy@alum.mit.edu>
+ * Guy Harris <guy@alum.mit.edu>
  *
- * $Id: packet-nbns.c,v 1.56 2001/09/17 02:07:00 guy Exp $
+ * $Id: packet-nbns.c,v 1.66 2001/12/03 03:59:37 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -40,7 +39,7 @@
 #include "packet.h"
 #include "packet-dns.h"
 #include "packet-netbios.h"
-#include "packet-smb.h"
+#include "packet-tcp.h"
 #include "prefs.h"
 
 static int proto_nbns = -1;
@@ -1155,10 +1154,8 @@ dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        proto_tree              *nbdgm_tree = NULL;
        proto_item              *ti = NULL;
        struct nbdgm_header     header;
-       int                     msglen;
        int                     flags;
        int                     message_index;
-       int                     max_data = tvb_length_remaining(tvb, offset);
        tvbuff_t                *next_tvb;
 
        static const value_string error_codes[] = {
@@ -1241,7 +1238,6 @@ dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        }
 
        offset += 10;
-       max_data -= 10;
 
        switch (header.msg_type) {
 
@@ -1256,7 +1252,6 @@ dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                }
 
                offset += 4;
-               max_data -= 4;
 
                /* Source name */
                len = get_nbns_name(tvb, offset, offset, name, &name_type);
@@ -1266,7 +1261,6 @@ dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                            "Source name", name, name_type);
                }
                offset += len;
-               max_data -= len;
 
                /* Destination name */
                len = get_nbns_name(tvb, offset, offset, name, &name_type);
@@ -1276,24 +1270,17 @@ dissect_nbdgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                            "Destination name", name, name_type);
                }
                offset += len;
-               max_data -= len;
 
                /*
                 * Here we can pass the packet off to the next protocol.
                 * Set the length of our top-level tree item to include
                 * only our stuff.
+                *
+                * XXX - take the datagram length into account?
                 */
                proto_item_set_len(ti, offset);
-               {
-                       const guint8    *next_pd;
-                       int             next_offset;
-
-                       next_tvb = tvb_new_subset(tvb, offset, -1, -1);
-                       tvb_compat(next_tvb, &next_pd, &next_offset);
-
-                       dissect_smb(next_pd, next_offset, pinfo->fd, tree,
-                           max_data);
-               }
+               next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+               dissect_netbios_payload(next_tvb, pinfo, tree);
                break;
 
        case NBDS_ERROR:
@@ -1379,10 +1366,11 @@ dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo,
        proto_item      *tf;
        guint8          msg_type;
        guint8          flags;
-       guint16         length;
+       int             length;
        int             len;
        char            name[(NETBIOS_NAME_LEN - 1)*4 + MAXDNAME];
        int             name_type;
+       gint            reported_len;
        tvbuff_t        *next_tvb;
 
        msg_type = tvb_get_guint8(tvb, offset);
@@ -1494,21 +1482,19 @@ dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo,
 
        case SESSION_MESSAGE:
          /*
-          * Here we can pass the packet off to the next protocol.
+          * Here we can pass the message off to the next protocol.
           * Set the length of our top-level tree item to include
           * only our stuff.
           */
          proto_item_set_len(ti, offset);
-         {
-               const guint8    *next_pd;
-               int             next_offset;
-
-               next_tvb = tvb_new_subset(tvb, offset, -1, -1);
-               tvb_compat(next_tvb, &next_pd, &next_offset);
-
-               dissect_smb(next_pd, next_offset, pinfo->fd, tree,
-                   max_data - 4);
-         }
+         len = tvb_length_remaining(tvb, offset);
+         reported_len = tvb_reported_length_remaining(tvb, offset);
+         if (len > length)
+           len = length;
+         if (reported_len > length)
+           reported_len = length;
+         next_tvb = tvb_new_subset(tvb, offset, len, reported_len);
+         dissect_netbios_payload(next_tvb, pinfo, tree);
          break;
 
        }
@@ -1518,24 +1504,25 @@ dissect_nbss_packet(tvbuff_t *tvb, int offset, packet_info *pinfo,
 static void
 dissect_nbss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
+       struct tcpinfo  *tcpinfo = pinfo->private_data;
        int             offset = 0;
-       guint8          msg_type;
        int             max_data;
+       guint8          msg_type;
+       guint8          flags;
+       guint32         length;
        int             len;
        gboolean        is_cifs;
+       proto_tree      *nbss_tree;
+       proto_item      *ti;
 
        if (check_col(pinfo->fd, COL_PROTOCOL))
                col_set_str(pinfo->fd, COL_PROTOCOL, "NBSS");
        if (check_col(pinfo->fd, COL_INFO))
                col_clear(pinfo->fd, COL_INFO);
 
-       msg_type = tvb_get_guint8(tvb, offset);
+       max_data = tvb_length(tvb);
 
-       /*
-        * XXX - we should set this based on both the length remaining
-        * and "length"....
-        */
-       max_data = tvb_length_remaining(tvb, offset);
+       msg_type = tvb_get_guint8(tvb, offset);
 
        if (pinfo->match_port == TCP_PORT_CIFS) {
                /*
@@ -1551,40 +1538,134 @@ dissect_nbss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                is_cifs = FALSE;
        }
 
-       /* Hmmm, it may be a continuation message ... */
-
-#define RJSHACK 1
-#ifdef RJSHACK
-       if (((msg_type != SESSION_REQUEST) && 
-            (msg_type != POSITIVE_SESSION_RESPONSE) &&
-            (msg_type != NEGATIVE_SESSION_RESPONSE) &&
-            (msg_type != RETARGET_SESSION_RESPONSE) &&
-            (msg_type != SESSION_KEEP_ALIVE) &&
-            (msg_type != SESSION_MESSAGE)) ||
-           ((msg_type == SESSION_MESSAGE) &&
-            (max_data < 8 || tvb_memeql(tvb, offset + 4, "\377SMB", 4) != 0))) {
-         /*
-          * Either the first byte isn't one of the known message types,
-          * or it's a session message but we either don't have enough
-          * data in the frame for the NBSS/CIFS header plus an SMB header,
-          * or we do but the message data doesn't begin with 0xFF S M B.
-          * Assume it's a continuation message.
-          */
-         if (check_col(pinfo->fd, COL_INFO)) {
-           col_add_fstr(pinfo->fd, COL_INFO, "NBSS Continuation Message");
-         }
+       /*
+        * This might be a continuation of an earlier message.
+        * (Yes, that might be true even if we're doing TCP reassembly,
+        * as the first TCP segment in the capture might start in the
+        * middle of an NBNS message.)
+        */
 
-         if (tree)
-           proto_tree_add_text(tree, tvb, offset, max_data, "Continuation data");
+       /*
+        * If this isn't reassembled data, check to see whether it
+        * looks like a continuation of a message.
+        * (If it is reassembled data, it shouldn't be a continuation,
+        * as reassembly should've gathered the continuations together
+        * into a message.)
+        */
+       if (!tcpinfo->is_reassembled) {
+               if (max_data < 4) {
+                       /*
+                        * Not enough data for an NBSS header; assume
+                        * it's a continuation of a message.
+                        *
+                        * XXX - if there's not enough data, we should
+                        * attempt to reassemble the data, if the first byte
+                        * is a valid message type.
+                        */
+                       goto continuation;
+               }
 
-         return;
-       }
-#endif
+               /*
+                * We have enough data for an NBSS header.
+                * Get the flags and length of the message,
+                * and see if they're sane.
+                */
+               if (is_cifs) {
+                       flags = 0;
+                       length = tvb_get_ntoh24(tvb, offset + 1);
+               } else {
+                       flags = tvb_get_guint8(tvb, offset + 1);
+                       length = tvb_get_ntohs(tvb, offset + 2);
+                       if (flags & NBSS_FLAGS_E)
+                               length += 65536;
+               }
+               if ((flags & (~NBSS_FLAGS_E)) != 0) {
+                       /*
+                        * A bogus flag was set; assume it's a continuation.
+                        */
+                       goto continuation;
+               }
+
+               switch (msg_type) {
 
+               case SESSION_MESSAGE:
+                       /*
+                        * This is variable-length.
+                        * All we know is that it shouldn't be zero.
+                        * (XXX - can we get zero-length messages?
+                        * Not with SMB, but perhaps other NetBIOS-based
+                        * protocols have them.)
+                        */
+                       if (length == 0)
+                               goto continuation;
+                       break;
+
+               case SESSION_REQUEST:
+                       /*
+                        * This is variable-length.
+                        * The names are DNS-encoded 32-byte values;
+                        * we need at least 2 bytes (one for each name;
+                        * actually, we should have more for the first
+                        * name, as there's no name preceding it so
+                        * there should be no compression), and we
+                        * shouldn't have more than 128 bytes (actually,
+                        * we shouldn't have that many).
+                        *
+                        * XXX - actually, MacOS X 10.1 (yes, that's
+                        * redundant, but that's what Apple calls it,
+                        * not MacOS X.1) puts names longer than 16
+                        * characters into session request messages,
+                        * so we can have more than 32 bytes of
+                        * name value, so we can have more than 128
+                        * bytes of data.
+                        */
+                       if (length < 2 || length > 256)
+                               goto continuation;
+                       break;
+
+               case POSITIVE_SESSION_RESPONSE:
+                       /*
+                        * This has no data, so the length must be zero.
+                        */
+                       if (length != 0)
+                               goto continuation;
+                       break;
+
+               case NEGATIVE_SESSION_RESPONSE:
+                       /*
+                        * This has 1 byte of data.
+                        */
+                       if (length != 1)
+                               goto continuation;
+                       break;
+
+               case RETARGET_SESSION_RESPONSE:
+                       /*
+                        * This has 6 bytes of data.
+                        */
+                       if (length != 6)
+                               goto continuation;
+                       break;
+
+               case SESSION_KEEP_ALIVE:
+                       /*
+                        * This has no data, so the length must be zero.
+                        */
+                       if (length != 0)
+                               goto continuation;
+                       break;
+
+               default:
+                       /*
+                        * Unknown message type; assume it's a continuation.
+                        */
+                       goto continuation;
+               }
+       }
        if (check_col(pinfo->fd, COL_INFO)) {
                col_add_fstr(pinfo->fd, COL_INFO,
-                   val_to_str(msg_type, message_types, "Unknown (%x)"));
+                   val_to_str(msg_type, message_types, "Unknown (%02x)"));
        }
 
        while (max_data > 0) {
@@ -1593,6 +1674,23 @@ dissect_nbss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                offset += len;
                max_data -= len;
        }
+
+       return;
+
+continuation:
+       /*
+        * It looks like a continuation.
+        */
+       if (check_col(pinfo->fd, COL_INFO))
+               col_add_fstr(pinfo->fd, COL_INFO, "NBSS Continuation Message");
+
+       if (tree) {
+               ti = proto_tree_add_item(tree, proto_nbss, tvb, 0,
+                   max_data, FALSE);
+               nbss_tree = proto_item_add_subtree(ti, ett_nbss);
+               proto_tree_add_text(nbss_tree, tvb, 0, max_data,
+                   "Continuation data");
+       }
 }
 
 void
@@ -1709,8 +1807,13 @@ proto_register_nbt(void)
 void
 proto_reg_handoff_nbt(void)
 {
-  dissector_add("udp.port", UDP_PORT_NBNS, dissect_nbns, proto_nbns);
-  dissector_add("udp.port", UDP_PORT_NBDGM, dissect_nbdgm, proto_nbdgm);
-  dissector_add("tcp.port", TCP_PORT_NBSS, dissect_nbss, proto_nbss);
-  dissector_add("tcp.port", TCP_PORT_CIFS, dissect_nbss, proto_nbss);
+  dissector_handle_t nbns_handle, nbdgm_handle, nbss_handle;
+
+  nbns_handle = create_dissector_handle(dissect_nbns, proto_nbns);
+  dissector_add("udp.port", UDP_PORT_NBNS, nbns_handle);
+  nbdgm_handle = create_dissector_handle(dissect_nbdgm, proto_nbdgm);
+  dissector_add("udp.port", UDP_PORT_NBDGM, nbdgm_handle);
+  nbss_handle = create_dissector_handle(dissect_nbss, proto_nbss);
+  dissector_add("tcp.port", TCP_PORT_NBSS, nbss_handle);
+  dissector_add("tcp.port", TCP_PORT_CIFS, nbss_handle);
 }