Ethereal-dev: Re: [Ethereal-dev] Custom protocol on top of TCP. (newbie question)

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

From: Heinitz Valentin <heinitz@xxxxxxxxxx>
Date: Fri, 27 Aug 2004 11:58:32 +0200
***********************
Postoffice Eckelmann AG: Ihr Mail wurde mit TrendMicro Interscan Messaging Security Suite überprüft, es enthält keine Viren.
***********-***********


Hello Alok,

thank You very much for this valuable "Get Startet manual"!!!
I could not beleive, as I saw it working!
Ethereal shows MYPROTO for the Messages on port 8443, and submenue
"My Protocol" appeared.

> See if this helps you, it is something I bummed from the POP protocol
Yes it did!!!

> To arrange that your dissector will be built as part of Ethereal, you
> must add the name of the source file for your dissector to the
> 'DISSECTOR_SRC' macro in the 'Makefile.common' file in the 'epan'
> directory. 
Could it be, that directory structures changed in new version? I downloaded
"nightly SVN archive" 2 days ago. All the packet-PROT.c files are in epan/dissectors.
So I copied the file packet-myproto.c there, and modified Makefile.common
also there.

>(Note that this is for modern versions of UNIX, so there
> is no 14-character limitation on file names, and for modern versions of
> Windows, so there is no 8.3-character limitation on file names.)
:-) What is Windows?


> You can run a simple websever on port 8443 (or change the TCP_PORT on
> top) and use it.
I tested it with 2 netcat processes.

I whant to thank You once again for the help,

   Have a nice day.

Valentin Heinitz


Alok <alokdube@xxxxxxxxxx>  wrote:
*************************************************************

See if this helps you, it is something I bummed from the POP protocol
file and commented things::

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>
/*#include "packet-myproto.h"*/
#include <string.h>
#include <glib.h>
#include <epan/packet.h>
#include <epan/strutil.h>

static int hf_myproto_response = -1;
static int hf_myproto_request = -1;
static int proto_myproto = -1;
static int hf_myproto = -1;
/*static int hf_proto = -1;*/

static gint ett_myproto = -1;
static gint ett_myproto_reqresp = -1;
/* making a reference to the dissector_handle_t (dont ask me why yet!!)*/
static dissector_handle_t data_handle;

/*TCP port on which the dissector works*/
#define TCP_PORT_MYPROTO            8443


/*static gboolean response_is_continuation(const guchar *data);*/

static void
dissect_myproto(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
        gboolean        is_request;
        gboolean    is_continuation;      
    proto_item    *ti;
  proto_tree      *myproto_tree, *reqresp_tree;
    gint        offset = 0;
    const guchar    *line;
    gint        next_offset;
    int        linelen;
    int        tokenlen;
    const guchar    *next_token;

    if (check_col(pinfo->cinfo, COL_PROTOCOL))
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "MYPROTO");

    /*
     * Find the end of the first line.
     *
     * Note that "tvb_find_line_end()" will return a value that is
     * not longer than what's in the buffer, so the "tvb_get_ptr()"
     * call won't throw an exception...<alok: whatver it means I
   * just gulped it but apparentlyit has something to do with POP
   * messages being plaintext terminating with EOL character>
     */
    linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
    line = tvb_get_ptr(tvb, offset, linelen);

/* we basically check if the destination port matches and if it does
 * we know it is a request
 * funny it does not match a syn but that is the way POP works,
 * a typical one would have to check
 * on SYN
*/
    if (pinfo->match_port == pinfo->destport) {
        is_request = TRUE;
        is_continuation = FALSE;
 
    } else {
        is_request = FALSE;
/*        is_continuation = response_is_continuation(line);*/
is_continuation = TRUE;
    }

    if (check_col(pinfo->cinfo, COL_INFO)) {
        /*
         * Put the first line from the buffer into the summary
         * if it's a myproto request or reply (but leave out the
         * line terminator).
         * Otherwise, just call it a continuation.
         */
        if (is_continuation)
            col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
        else
            col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s",
                is_request ? "Request" : "Response",
                format_text(line, linelen));
    }

    if (tree) {
        ti = proto_tree_add_item(tree, proto_myproto, tvb, offset, -1,
            FALSE);
        myproto_tree = proto_item_add_subtree(ti, ett_myproto);

        if (is_continuation) {
            /*
             * Put the whole packet into the tree as data.
             */
            call_dissector(data_handle,tvb, pinfo, myproto_tree);
            return;
        }

        if (is_request) {
            proto_tree_add_boolean_hidden(myproto_tree,
                hf_myproto_request, tvb, 0, 0, TRUE);
        } else {
            proto_tree_add_boolean_hidden(myproto_tree,
                hf_myproto_response, tvb, 0, 0, TRUE);
        }

        /*
         * Put the line into the protocol tree.
         */
        ti = proto_tree_add_text(myproto_tree, tvb, offset,
            next_offset - offset, "%s",
            tvb_format_text(tvb, offset, next_offset - offset));
        reqresp_tree = proto_item_add_subtree(ti, ett_myproto_reqresp);

        /*
         * Extract the first token, and, if there is a first
         * token, add it as the request or reply code.
         */
        tokenlen = get_token_len(line, line + linelen, &next_token);
        if (tokenlen != 0) {
            if (is_request) {
                proto_tree_add_text(reqresp_tree, tvb, offset,
                    tokenlen, "Request: %s",
                    format_text(line, tokenlen));
            } else {
                proto_tree_add_text(reqresp_tree, tvb, offset,
                    tokenlen, "Response: %s",
                    format_text(line, tokenlen));
            }
            offset += next_token - line;
            linelen -= next_token - line;
            line = next_token;
        }

        /*
         * Add the rest of the first line as request or
         * reply data.
         */
        if (linelen != 0) {
            if (is_request) {
                proto_tree_add_text(reqresp_tree, tvb, offset,
                    linelen, "Request Arg: %s",
                    format_text(line, linelen));
            } else {
                proto_tree_add_text(reqresp_tree, tvb, offset,
                    linelen, "Response Arg: %s",
                    format_text(line, linelen));
            }
        }
        offset = next_offset;

        /*
         * Show the rest of the request or response as text,
         * a line at a time.
         */
        while (tvb_offset_exists(tvb, offset)) {
            /*
             * Find the end of the line.
             */
            linelen = tvb_find_line_end(tvb, offset, -1,
                &next_offset, FALSE);

            /*
             * Put this line.
             */
            proto_tree_add_text(myproto_tree, tvb, offset,
                next_offset - offset, "%s",
                tvb_format_text(tvb, offset, next_offset - offset));
            offset = next_offset;
        }
    }
}
/*since I bummed from POP this is POP response, but I plan to go the syn
 +ack way to test new connnections for my lousy code*/
/*static gboolean response_is_continuation(const guchar *data)
{
  if (strncmp(data, "+OK", strlen("+OK")) == 0)
    return FALSE;

  if (strncmp(data, "-ERR", strlen("-ERR")) == 0)
    return FALSE;

  return TRUE;
} */

void
proto_register_myproto(void)
{

  static hf_register_info hf[] = {
    { &hf_myproto_response,
      { "Response",           "myproto.response",
    FT_BOOLEAN, BASE_NONE, NULL, 0x0,
          "TRUE if myproto response", HFILL }},

    { &hf_myproto_request,
      { "Request",            "myproto.request",
    FT_BOOLEAN, BASE_NONE, NULL, 0x0,
          "TRUE if myproto request", HFILL }}
  };
  static gint *ett[] = {
    &ett_myproto,
    &ett_myproto_reqresp,
  };

  proto_myproto = proto_register_protocol("MY Protocol", "MYPROTO",
"myproto");
  proto_register_field_array(proto_myproto, hf, array_length(hf));
  proto_register_subtree_array(ett, array_length(ett));
}

void
proto_reg_handoff_myproto(void)
{
  dissector_handle_t myproto_handle;

  myproto_handle = create_dissector_handle(dissect_myproto, proto_myproto);
  dissector_add("tcp.port", TCP_PORT_MYPROTO, myproto_handle);
  data_handle = find_dissector("data");      /*same as data_handle_t*/
}


/*After this you need to add the dissector to the Makefile.common as
  *stated in the readme.developer
To arrange that your dissector will be built as part of Ethereal, you
must add the name of the source file for your dissector to the
'DISSECTOR_SRC' macro in the 'Makefile.common' file in the 'epan'
directory.  (Note that this is for modern versions of UNIX, so there
is no 14-character limitation on file names, and for modern versions of
Windows, so there is no 8.3-character limitation on file names.)
*/

============================================================

the dissector registration routines are fine. and it builds too.

You can run a simple websever on port 8443 (or change the TCP_PORT on
top) and use it.
-HTH