Ethereal-dev: Re: [Ethereal-dev] New dissector for Red Hat/Fedora netdump

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Eric Paris <eparis@xxxxxxxxxxxxxx>
Date: Mon, 25 Apr 2005 14:14:03 -0400
Guess I'm supposed to give an svn diff, so here it is.

Eric

On Mon, 2005-04-25 at 14:10 -0400, Eric Paris wrote:
> Attached is a file packet-netdump.c which should dissect netdump
> packets.  Netdump is the protocol used to send crash information like
> the stack and memory contents to a netdump server when a linux machine
> panics/opps.  
> 
> This is my first attempt at a dissector, so please let me have any
> comments on any problems you see.
> 
> Netdump uses port UDP 6666 which is also defined by packet-sigcomp.c.  I
> don't have any traces which result in parsing these type of packets so
> I'm not sure how to make sure it is still picking those up.  I found
> that just registering port 6666 with dissector_add caused the sigcomp to
> still get tried and my netdump to never get tried.  So I registered with
> heur_dissector_add and it started trying my dissector second.  So I can
> only assume that it will get those others.   I'm not sure what the right
> way is to do this.  Please comment if this was not right or if there is
> a better way.
> 
> I have a netdump capture with netdump traffic but its about 40 megs long
> (dumping memory does generate a lot of traffic), please let me know if
> access to this is needed.
> 
> Eric
> _______________________________________________
> Ethereal-dev mailing list
> Ethereal-dev@xxxxxxxxxxxx
> http://www.ethereal.com/mailman/listinfo/ethereal-dev
Index: epan/dissectors/Makefile.common
===================================================================
--- epan/dissectors/Makefile.common	(revision 14182)
+++ epan/dissectors/Makefile.common	(working copy)
@@ -402,6 +402,7 @@
 	packet-ndmp.c	\
 	packet-ndps.c	\
 	packet-netbios.c	\
+	packet-netdump.c	\
 	packet-netflow.c	\
 	packet-netsync.c \
 	packet-nettl.c	\
Index: epan/dissectors/packet-netdump.c
===================================================================
--- epan/dissectors/packet-netdump.c	(revision 0)
+++ epan/dissectors/packet-netdump.c	(revision 0)
@@ -0,0 +1,323 @@
+/* packet-netdump.c
+ * 
+ * Routines for netdump dissection.  Netdump is the crash dump
+ * protocol used by Red Hat to write kernel stack trace and
+ * memory contents to a network sever during an opps or panic
+ *
+ * Copyright 2000, Eric_Paris <ethereal-netdump@xxxxxxxxxxxxxx>
+ *
+ * $Id: README.developer 12979 2005-01-07 11:59:05Z guy $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@xxxxxxxxxxxx>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <address.h>
+#include <epan/packet.h>
+#include <epan/conversation.h>
+
+#define UDP_PORT_NETDUMP 6666
+
+static int proto_netdump = -1;
+static int hf_netdump_magicnumber = -1;
+static int hf_netdump_nr = -1;
+static int hf_netdump_command = -1;
+static int hf_netdump_from = -1;
+static int hf_netdump_to = -1;
+static int hf_netdump_code = -1;
+static int hf_netdump_info = -1;
+static int hf_netdump_version = -1;
+
+static gint ett_netdump = -1;
+
+static dissector_handle_t netdump_handle;
+
+enum netdump_commands
+{
+  COMM_NONE = 0,
+  COMM_SEND_MEM = 1,
+  COMM_EXIT = 2,
+  COMM_REBOOT = 3,
+  COMM_HELLO = 4,
+  COMM_GET_NR_PAGES = 5,
+  COMM_GET_PAGE_SIZE = 6,
+  COMM_START_NETDUMP_ACK = 7,
+  COMM_GET_REGS = 8,
+  COMM_SHOW_STATE = 9
+};
+
+static const value_string netdump_command_vals[] = {
+  {COMM_NONE, "COMM_NONE, Unknown to Author"},
+  {COMM_SEND_MEM, "COMM_SEND_MEM, Request to Send Memory"},
+  {COMM_EXIT, "COMM_EXIT, Unknown to Author"},
+  {COMM_REBOOT, "COMM_REBOOT, Request to Reboot Client"},
+  {COMM_HELLO, "COMM_HELLO, Hello Message"},
+  {COMM_GET_NR_PAGES, "COMM_GET_NR_PAGES, Request Number of Pages on Client"},
+  {COMM_GET_PAGE_SIZE, "COMM_GET_PAGE_SIZE, Request the Size of a Page"},
+  {COMM_START_NETDUMP_ACK,
+   "COMM_START_NETDUMP_ACK, Server Responce to REPLY_START_NETDUMP"},
+  {COMM_GET_REGS, "COMM_GET_REGS, Request for All Registers"},
+  {COMM_SHOW_STATE, "COMM_SHOW_STATE, Request to Show Client State"}
+};
+
+enum netdump_replies
+{
+  REPLY_NONE = 0,
+  REPLY_ERROR = 1,
+  REPLY_LOG = 2,
+  REPLY_MEM = 3,
+  REPLY_RESERVED = 4,
+  REPLY_HELLO = 5,
+  REPLY_NR_PAGES = 6,
+  REPLY_PAGE_SIZE = 7,
+  REPLY_START_NETDUMP = 8,
+  REPLY_END_NETDUMP = 9,
+  REPLY_REGS = 10,
+  REPLY_MAGIC = 11,
+  REPLY_SHOW_STATE = 12
+};
+
+static const value_string netdump_reply_vals[] = {
+  {REPLY_NONE, " REPLY_NONE, Unknown to Author"},
+  {REPLY_ERROR, "REPLY_ERROR, Error"},
+  {REPLY_LOG, "REPLY_LOG, Log Dump"},
+  {REPLY_MEM, "REPLY_MEM, Memory Dump"},
+  {REPLY_RESERVED, "REPLY_RESERVED, Unknown to Author"},
+  {REPLY_HELLO,
+   "REPLY_HELLO, Client Responce to COMM_HELLO (complete handshake)"},
+  {REPLY_NR_PAGES, "REPLY_NR_PAGES, Client Number of Pages"},
+  {REPLY_PAGE_SIZE, "REPLY_PAGE_SIZE, Client Page Size"},
+  {REPLY_START_NETDUMP, "REPLY_START_NETDUMP, Request to Start a Netdump"},
+  {REPLY_END_NETDUMP, "REPLY_END_NETDUMP, Unknown to Author"},
+  {REPLY_REGS, "REPLY_REGS, Client Registers"},
+  {REPLY_MAGIC, "REPLY_MAGIC, Magic Number"},
+  {REPLY_SHOW_STATE, "REPLY_SHOW_STATE, Client State"}
+};
+
+struct netdump_conversation_data_t
+{
+  address client;
+  address server;
+};
+
+/* Code to actually dissect the packets */
+static int
+dissect_netdump (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+
+/* Set up structures needed to add the protocol subtree and manage it */
+  proto_item *ti;
+  proto_tree *netdump_tree;
+  conversation_t *conversation;
+  struct netdump_conversation_data_t *netdump_conversation_data = NULL;
+
+
+  /*
+   * we are not netdump if talking to syslog, that is actually console log and should
+   * be parsed as a standard syslog message
+   */
+  if (pinfo->destport == 514)
+    return 0;
+
+  /* hopefully this will make the conversation match exactly */
+  conversation =
+    find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
+		       pinfo->srcport, pinfo->destport, 0);
+  if (conversation == NULL)
+    {
+      /* 
+       * The conversation is created matching exactly on the source/dest
+       * address/port.  That way we won't accidentally match on other
+       * messages.
+       */
+      guint options = 0;
+      conversation =
+	conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
+			  pinfo->srcport, pinfo->destport, options);
+      conversation_set_dissector (conversation, netdump_handle);
+      netdump_conversation_data =
+	malloc (sizeof (struct netdump_conversation_data_t));
+      COPY_ADDRESS (&(netdump_conversation_data->client), &(pinfo->net_src));
+      COPY_ADDRESS (&(netdump_conversation_data->server), &(pinfo->net_dst));
+      conversation_add_proto_data (conversation, proto_netdump,
+				   netdump_conversation_data);
+    }
+  else
+    {
+      netdump_conversation_data =
+	conversation_get_proto_data (conversation, proto_netdump);
+    }
+
+/* Make entries in Protocol column and Info column on summary display */
+  if (check_col (pinfo->cinfo, COL_PROTOCOL))
+    col_set_str (pinfo->cinfo, COL_PROTOCOL, "NETDUMP");
+
+  if (check_col (pinfo->cinfo, COL_INFO))
+    col_clear (pinfo->cinfo, COL_INFO);
+
+  if (check_col (pinfo->cinfo, COL_INFO))
+    col_add_fstr (pinfo->cinfo, COL_INFO, "Net Dump");
+
+  if (tree)
+    {
+      gint offset = 0;
+      guint16 bytes_remaining = 0;
+
+/* create display subtree for the protocol */
+      ti = proto_tree_add_item (tree, proto_netdump, tvb, 0, -1, FALSE);
+
+      netdump_tree = proto_item_add_subtree (ti, ett_netdump);
+
+      bytes_remaining = tvb_reported_length_remaining (tvb, offset);
+/* 
+ * choose which info to display.  we pick server/client based on who initiated
+ * the conversions.  The initiator information should be stored in the 
+ * netdump_conversation_data->server field
+ */
+      if (ADDRESSES_EQUAL (&pinfo->src, &netdump_conversation_data->server))
+	{
+	  proto_tree_add_item (netdump_tree,
+			       hf_netdump_magicnumber, tvb, offset, 8, FALSE);
+	  offset += 8;
+
+	  proto_tree_add_item (netdump_tree,
+			       hf_netdump_nr, tvb, offset, 4, FALSE);
+	  offset += 4;
+
+	  proto_tree_add_item (netdump_tree,
+			       hf_netdump_command, tvb, offset, 4, FALSE);
+	  offset += 4;
+
+	  proto_tree_add_item (netdump_tree,
+			       hf_netdump_from, tvb, offset, 4, FALSE);
+	  offset += 4;
+
+	  proto_tree_add_item (netdump_tree,
+			       hf_netdump_to, tvb, offset, 4, FALSE);
+	  offset += 4;
+	}
+      else
+	{
+
+	  proto_tree_add_item (netdump_tree,
+			       hf_netdump_version, tvb, offset, 1, FALSE);
+	  offset += 1;
+
+	  proto_tree_add_item (netdump_tree,
+			       hf_netdump_nr, tvb, offset, 4, FALSE);
+	  offset += 4;
+
+	  proto_tree_add_item (netdump_tree,
+			       hf_netdump_code, tvb, offset, 4, FALSE);
+	  offset += 4;
+
+	  proto_tree_add_item (netdump_tree,
+			       hf_netdump_info, tvb, offset, 4, FALSE);
+	  offset += 4;
+
+	  bytes_remaining = tvb_reported_length_remaining (tvb, offset);
+	  if (bytes_remaining)
+	    proto_tree_add_text (netdump_tree, tvb, offset, -1,
+				 "Data (%d bytes)",
+				 tvb_reported_length_remaining (tvb, offset));
+	}
+      return tvb_length (tvb);
+    }
+}
+
+static gboolean
+dissect_netdump_heur (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+  return dissect_netdump (tvb, pinfo, tree);
+}
+
+/* Register the protocol with Ethereal */
+
+void
+proto_register_netdump (void)
+{
+  static hf_register_info hf[] = {
+    {&hf_netdump_magicnumber,
+     {"magicnumber", "netdump.magicnumber",
+      FT_UINT64, BASE_HEX, NULL, 0x0,
+      "Magic Number", HFILL}
+     },
+    {&hf_netdump_nr,
+     {"nr", "netdump.nr",
+      FT_UINT32, BASE_DEC, NULL, 0x0,
+      "nr Number", HFILL}
+     },
+    {&hf_netdump_command,
+     {"command", "netdump.command",
+      FT_UINT32, BASE_DEC, VALS (netdump_command_vals), 0x0,
+      "Command", HFILL}
+     },
+    {&hf_netdump_from,
+     {"from", "netdump.from",
+      FT_UINT32, BASE_HEX, NULL, 0x0,
+      "From", HFILL}
+     },
+    {&hf_netdump_to,
+     {"to", "netdump.to",
+      FT_UINT32, BASE_HEX, NULL, 0x0,
+      "To", HFILL}
+     },
+    {&hf_netdump_version,
+     {"version", "netdump.version",
+      FT_UINT8, BASE_DEC, NULL, 0x0,
+      "Effective Version", HFILL}
+     },
+    {&hf_netdump_code,
+     {"code", "netdump.code",
+      FT_UINT32, BASE_DEC, VALS (netdump_reply_vals), 0x0,
+      "Code", HFILL}
+     },
+    {&hf_netdump_info,
+     {"info", "netdump.info",
+      FT_UINT32, BASE_DEC, NULL, 0x0,
+      "Info", HFILL}
+     },
+  };
+
+  static gint *ett[] = {
+    &ett_netdump,
+  };
+
+  proto_netdump = proto_register_protocol ("Net Dump", "NetDump", "netdump");
+  proto_register_field_array (proto_netdump, hf, array_length (hf));
+  proto_register_subtree_array (ett, array_length (ett));
+  netdump_handle = new_create_dissector_handle (dissect_netdump,
+						proto_netdump);
+}
+
+void
+proto_reg_handoff_netdump (void)
+{
+  dissector_add ("udp.port", UDP_PORT_NETDUMP, netdump_handle);
+  heur_dissector_add ("udp", dissect_netdump_heur, proto_netdump);
+}