Wireshark-dev: Re: [Wireshark-dev] Has anyone created an XDR to Dissector tool?

From: Richard Sharpe <realrichardsharpe@xxxxxxxxx>
Date: Fri, 2 Sep 2016 08:03:27 -0700
For those following along at home, here is a WIP patch against the
glibc master version of rpcgen.

It builds and runs and generates an incomplete dissector at this
stage, but it shows where I think I am headed.

I am sure I can do with some feedback even at this early stage, and
will likely have something that generates a complete dissector by
Monday some time.

Of course, whether or not the glibc folks want it is another matter.

-- 
Regards,
Richard Sharpe
(何以解憂?唯有杜康。--曹操)
From 62fa23aa3571fb6578e1c27b702bde1bcfdfd078 Mon Sep 17 00:00:00 2001
From: Richard Sharpe <rsharpe@xxxxxxxxx>
Date: Fri, 2 Sep 2016 07:59:34 -0700
Subject: [PATCH] WIP of the Wireshark dissector for XDR etc.

---
 sunrpc/Makefile        |   2 +-
 sunrpc/rpc_main.c      |  63 ++++++++++++++++++--
 sunrpc/rpc_wireshark.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++
 sunrpc/rpc_wireshark.h |  10 ++++
 4 files changed, 226 insertions(+), 7 deletions(-)
 create mode 100644 sunrpc/rpc_wireshark.c
 create mode 100644 sunrpc/rpc_wireshark.h

diff --git a/sunrpc/Makefile b/sunrpc/Makefile
index 789ef42..ed5e9f0 100644
--- a/sunrpc/Makefile
+++ b/sunrpc/Makefile
@@ -92,7 +92,7 @@ endif
 install-bin := rpcgen
 rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
 	      rpc_scan.o rpc_util.o rpc_svcout.o rpc_clntout.o \
-	      rpc_tblout.o rpc_sample.o
+	      rpc_tblout.o rpc_sample.o rpc_wireshark.o
 extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
 others += rpcgen
 
diff --git a/sunrpc/rpc_main.c b/sunrpc/rpc_main.c
index 0a51e2c..214f6b2 100644
--- a/sunrpc/rpc_main.c
+++ b/sunrpc/rpc_main.c
@@ -49,6 +49,7 @@
 #include "rpc_parse.h"
 #include "rpc_util.h"
 #include "rpc_scan.h"
+#include "rpc_wireshark.h"
 #include "proto.h"
 
 #include "../version.h"
@@ -68,6 +69,7 @@ struct commandline
     int tflag;			/* dispatch Table file */
     int Ssflag;			/* produce server sample code */
     int Scflag;			/* produce client sample code */
+    int Wflag;                  /* Produce a wireshark dissector */
     int makefileflag;		/* Generate a template Makefile */
     const char *infile;		/* input module name */
     const char *outfile;	/* output module name */
@@ -125,6 +127,8 @@ static void svc_output (const char *infile, const char *define,
 			int extend, const char *outfile);
 static void clnt_output (const char *infile, const char *define,
 			 int extend, const char *outfile);
+static void wireshark_output (const char *infile, const char *define,
+			      int extend, const char *outfile);
 static void mkfile_output (struct commandline *cmd);
 static int do_registers (int argc, const char *argv[]);
 static void addarg (const char *cp);
@@ -183,7 +187,7 @@ main (int argc, const char *argv[])
     usage (stderr, 1);
 
   if (cmd.cflag || cmd.hflag || cmd.lflag || cmd.tflag || cmd.sflag ||
-      cmd.mflag || cmd.nflag || cmd.Ssflag || cmd.Scflag)
+      cmd.mflag || cmd.nflag || cmd.Ssflag || cmd.Scflag || cmd.Wflag)
     {
       checkfiles (cmd.infile, cmd.outfile);
     }
@@ -205,6 +209,8 @@ main (int argc, const char *argv[])
     svc_output (cmd.infile, "-DRPC_SERVER", DONT_EXTEND, cmd.outfile);
   else if (cmd.Scflag)
     clnt_output (cmd.infile, "-DRPC_CLIENT", DONT_EXTEND, cmd.outfile);
+  else if (cmd.Wflag)
+    wireshark_output (cmd.infile, "-DRPC_XDR", DONT_EXTEND, cmd.outfile);
   else if (cmd.makefileflag)
     mkfile_output (&cmd);
   else
@@ -364,7 +370,7 @@ open_input (const char *infile, const char *define)
       putarg (1, CPPFLAGS);
       addarg (define);
       if (infile)
-	addarg (infile);
+	addarg (infilename);
       addarg ((char *) NULL);
       close (1);
       dup2 (pd[1], 1);
@@ -389,6 +395,7 @@ open_input (const char *infile, const char *define)
       perror (infilename);
       crash ();
     }
+  printf("execvp'ing %s %s %s %s\n", CPP, CPPFLAGS, define, infilename);
 }
 
 /* Close the connection to the C-preprocessor and check for successfull
@@ -909,6 +916,47 @@ clnt_output (const char *infile, const char *define, int extend,
   close_output (outfilename);
 }
 
+/*
+ * generate wireshark dissector
+ *
+ * Pass over the list of definitions as many times as needed to 
+ * generate the following:
+ *
+ * 1. The Preamble containing includes, the program define and the 
+ *    forward declarations needed.
+ * 2. The ett values
+ * 3. The hf values needed.
+ * 4. The value strings needed.
+ * 5. The structure dissections.
+ * 6. The program dissections.
+ * 7. The epilog containing initialization of the hf and ett values
+ *    and etc.
+ *
+ *  We can do that because we have all we need in the list.
+ */
+static void
+wireshark_output (const char *infile, const char *define, int extend,
+	  const char *outfile)
+{
+  definition *def;
+  const char *outfilename;
+
+  open_input (infile, define);
+  outfilename = extend ? extendfile (infile, outfile) : outfile;
+  open_output (infile, outfilename);
+  checkfiles (infile, outfilename);
+
+  while ((def = get_definition ()) != NULL)
+    {
+
+    }
+
+  write_wireshark();
+
+  close_input ();
+  close_output (outfilename);
+}
+
 static const char space[] = " ";
 
 static char *
@@ -1131,9 +1179,9 @@ checkfiles (const char *infile, const char *outfile)
 	  fprintf (stderr,
 		   /* TRANS: the file will not be removed; this is an
 		      TRANS: informative message.  */
-		   _("file `%s' already exists and may be overwritten\n"),
-		   outfile);
-	  crash ();
+		   _("file `%s' already exists and may be overwritten: %s\n"),
+		   outfile, strerror(errno));
+	  /*crash ();*/
 	}
     }
 }
@@ -1200,6 +1248,7 @@ parseargs (int argc, const char *argv[], struct commandline *cmd)
 		case 'l':
 		case 'm':
 		case 't':
+		case 'W':
 		  if (flag[c])
 		    return 0;
 		  flag[c] = 1;
@@ -1339,6 +1388,7 @@ parseargs (int argc, const char *argv[], struct commandline *cmd)
   cmd->tflag = flag['t'];
   cmd->Ssflag = flag['S'];
   cmd->Scflag = flag['C'];
+  cmd->Wflag = flag['W'];
   cmd->makefileflag = flag['M'];
 
 #ifndef _RPC_THREAD_SAFE_
@@ -1377,7 +1427,8 @@ parseargs (int argc, const char *argv[], struct commandline *cmd)
 
   /* check no conflicts with file generation flags */
   nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag +
-    cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag + cmd->Scflag;
+    cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag + cmd->Scflag +
+    cmd->Wflag;
 
   if (nflags == 0)
     {
diff --git a/sunrpc/rpc_wireshark.c b/sunrpc/rpc_wireshark.c
new file mode 100644
index 0000000..8677d14
--- /dev/null
+++ b/sunrpc/rpc_wireshark.c
@@ -0,0 +1,158 @@
+/*      @(#)rpc_wireshark.c  1.0  16/09/01
+ *
+ * Copyright to be determined ...
+ *
+ * rpc_wireshark.h, Definitions for the generation of a wireshark 
+ * dissector in rpcgen
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "rpc/types.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+#include "proto.h"
+
+static void write_wireshark_boilerplate(definition *def);
+
+void write_wireshark(void)
+{
+  list *l;
+  definition *def, *prog = NULL;
+
+  /* Handle the prelude ... */
+  for (l = defined; l != NULL; l = l->next)
+    {
+      def = (definition *) l->val;
+      if (def->def_kind == DEF_PROGRAM)
+	{
+          prog = def;
+	  write_wireshark_boilerplate (def);
+	}
+    }
+
+  /*
+   * Now, do all the forward declarations we need.
+   * We need one for each data structure and 
+   * one for each function in version defs.
+   *
+   * If there is no program definition, the structure names
+   * do not need qualification as they have to be unique anyway.
+  */
+  for (l = defined; l != NULL; l = l->next)
+    {
+      version_list *v = NULL;
+      proc_list *p = NULL;
+
+      def = (definition *) l->val;
+      switch (def->def_kind) {
+        case DEF_STRUCT:
+        case DEF_UNION:
+          fprintf(fout, "%sdissect_%s(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);\n",
+                  (prog ? "static " : ""), def->def_name);
+          break;
+
+        case DEF_PROGRAM:
+          for (v = def->def.pr.versions; v != NULL; v = v->next)
+            {
+              for (p = v->procs; p != NULL; p = p->next)
+                {
+                  const char * tplt = "static dissect_%s_%s(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);\n";
+                  fprintf(fout, tplt, p->proc_name, "call");
+                  fprintf(fout, tplt, p->proc_name, "reply");
+                }
+            }
+          break;
+
+        default:
+          break;
+      }
+    } 
+
+  /* Insert the ett fields */
+  fprintf(fout, "\n");
+  if (prog)
+    fprintf(fout, "static gint ett_%s\n", prog->def_name);
+
+  for (l = defined; l != NULL; l = l->next)
+    {
+      version_list *v = NULL;
+      proc_list *p = NULL;
+
+      def = (definition *) l->val;
+      switch (def->def_kind) {
+        case DEF_STRUCT:
+        case DEF_UNION:
+          fprintf(fout, "static gint ett_%s;\n", def->def_name);
+          break;
+
+        /* Not clear we need these */
+        case DEF_PROGRAM:
+          for (v = def->def.pr.versions; v != NULL; v = v->next)
+            {
+              for (p = v->procs; p != NULL; p = p->next)
+                {
+                  fprintf(fout, "static gint ett_%s;\n", p->proc_name);
+                }
+            }
+          break;
+
+        default:
+          break;
+        }
+    }
+}
+ 
+static void write_wireshark_boilerplate(definition *def)
+{
+    fprintf(fout,
+"/* packet-%s.c\n"
+" * Routines for %s dissection\n"
+" * Copyright %s, %s\n"
+" *\n"
+" * Wireshark - Network traffic analyzer\n"
+" * By Gerald Combs <gerald@xxxxxxxxxxxxx>\n"
+" * Copyright 1998 Gerald Combs\n"
+" *\n"
+" * Portions copied shamelessly from packet-nfs.c\n"
+" *\n"
+" * This program is free software; you can redistribute it and/or\n"
+" * modify it under the terms of the GNU General Public License\n"
+" * as published by the Free Software Foundation; either version 2\n"
+" * of the License, or (at your option) any later version.\n"
+" *\n"
+" * This program is distributed in the hope that it will be useful,\n"
+" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
+" * GNU General Public License for more details.\n"
+" *\n"
+" * You should have received a copy of the GNU General Public License\n"
+" * along with this program; if not, write to the Free Software\n"
+" * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n"
+" *\n"
+" * GENERATED BY RPCGEN. DO NOT DO SERIOUS EDITS.\n"
+" */\n"
+"\n"
+"#include \"config.h\"\n"
+"\n"
+"#include <stdio.h>\n"
+"\n"
+"#include <epan/packet.h>\n"
+"#include <epan/prefs.h>\n"
+"#include <epan/exceptions.h>\n"
+"#include <epan/expert.h>\n"
+"#include <epan/to_str.h>\n"
+"#include <epan/decode_as.h>\n"
+"#include <wsutil/crc16.h>\n"
+"#include <wsutil/crc32.h>\n"
+"#include \"packet-rpc.h\"\n"
+"\n"
+"#define %s %s\n\n"
+"void proto_register_%s(void);\n"
+"void proto_reg_handoff_%s(void);\n\n",
+           def->def_name, def->def_name, "2016", "SomeDude",
+           def->def_name, def->def.pr.prog_num,
+	   def->def_name, def->def_name);
+
+  /* TODO: Fix the year and pickyp the copyright somehow. */
+}
diff --git a/sunrpc/rpc_wireshark.h b/sunrpc/rpc_wireshark.h
new file mode 100644
index 0000000..713f7cb
--- /dev/null
+++ b/sunrpc/rpc_wireshark.h
@@ -0,0 +1,10 @@
+/*      @(#)rpc_wireshark.h  1.0  16/09/01
+ *
+ * Copyright to be determined ...
+ *
+ * rpc_wireshark.h, Definitions for the generation of a wireshark 
+ * dissector in rpcgen
+ */
+
+
+void write_wireshark (void);
-- 
2.4.3