Ethereal-dev: [Ethereal-dev] TCP Sequence Number Analysis Tap (skeleton, request for comments)

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

From: Jason House <jhouse@xxxxxxxxx>
Date: Thu, 19 Jun 2003 20:57:02 -0400
The attached file is a skeleton for a tap that tracks conversations. I wanted to get some feedback and reaction to it.

Each instance of the tap creates a field (with the same name) that it uses as its protocol identifier for conversations. Fields and protocols are allocated from the same number pool, but multiple fields of the same name are allowed to exist (unlike protocols which must be unique). The tap (in registration) also registers itself as a protocol. This appears to be unnecessary since I believe fields can be registered without a parent protocol. I figured, however, that the protocol feature might actually be useful. Any interesting ideas on how that could be useful? The rest of the code is really just a trivial implementation of conversation tracking. Doing multiple -z options would not cause any conflict in conversation data... I think that the naming of the skeleton and the title of this e-mail probably indicate where I want to see this go... It may eventually breath life into a revised form of my old tcp_close tap ;) ... Or at the very least allow the evolution of similar, more useful tcp taps.
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <epan/conversation.h>
#include <epan/packet_info.h>
#include <epan/packet.h>
#include "tap.h"
#include "register.h"

int tcpseq_protocol_id;

typedef struct
{
  int field_id;
} tcpseq_t;


struct tcpseq_analysis
{
  int conversation_number;
};

static struct tcpseq_analysis *
get_tcpseq_conversation_data(packet_info *pinfo, int field_id)
{
	conversation_t *conv=NULL;
	struct tcpseq_analysis *tcpd=NULL;
	static int conversation_number = 0;

	/* Have we seen this conversation before? */
	if( (conv=find_conversation(&pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0)) == NULL){
		/* No this is a new conversation. */
		conv=conversation_new(&pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
	}

	/* check if we have any data for this conversation */
	tcpd=conversation_get_proto_data(conv, field_id);
	if(!tcpd){
		/* No no such data yet. Allocate and init it */
	  tcpd = (struct tcpseq_analysis*) malloc(sizeof(struct tcpseq_analysis));
	  tcpd->conversation_number = ++conversation_number;
	  conversation_add_proto_data(conv, field_id, tcpd);
	  printf("TCP tap allocating new conversation data (conversation #%d\n", conversation_number);
	}

	return tcpd;
}


static int
tcpseq_packet(tcpseq_t *td, packet_info *pinfo, epan_dissect_t *det _U_, void *vtr)
{
  struct tcpseq_analysis *tcpd = get_tcpseq_conversation_data(pinfo, td->field_id);
  printf("TCP tap identified by field id %5d, found a TCP packet in identified conversation #%d\n",
	 td->field_id, tcpd->conversation_number);
  return 0;
}

static void
tcpseq_draw(tcpseq_t *td)
{
}

void tcpseq_init(char *optarg)
{
  char *filter = NULL;
  GString *error_string = NULL;
  tcpseq_t *td = malloc(sizeof(tcpseq_t));
  static header_field_info *same_name_prev = NULL;
  hf_register_info *hf = (hf_register_info*) malloc(sizeof(hf_register_info));

  hf->p_id = &td->field_id;
  hf->hfinfo.name    = "TCP Sequence Number Analysis Instance";
  hf->hfinfo.abbrev  = "tcp.seq.instance";
  hf->hfinfo.type    = FT_UINT8;
  hf->hfinfo.display = BASE_DEC;
  hf->hfinfo.strings = NULL;
  hf->hfinfo.bitmask = 0x0;
  hf->hfinfo.blurb   = "Tap internal field (for now)";
  hf->hfinfo.id      = -1;
  hf->hfinfo.parent  = -1;
  hf->hfinfo.bitshift= 0;
  hf->hfinfo.same_name_next = NULL;
  hf->hfinfo.same_name_prev = NULL;

  proto_register_field_array(tcpseq_protocol_id, hf, 1);
  if (same_name_prev != NULL){
    hf->hfinfo.same_name_prev = same_name_prev;
    same_name_prev->same_name_next = &hf->hfinfo;
  }    
  error_string=register_tap_listener("tcp", td, filter, NULL, (void*)tcpseq_packet, (void*)tcpseq_draw);
  if(error_string){
  }
}

void
register_tap_listener_tcpseq(void)
{
  tcpseq_protocol_id = proto_register_protocol("TCP Sequence Number Analysis", "TCPSEQ", "tap.tcp.seq");
  register_ethereal_tap("tcp,seq,", tcpseq_init);
}