Building A Basic Dissector Module (over tcp)

This page will provide you with all of the basic information required to create an Xplico dissector for a protocol that uses TCP (e.g. HTTP, Telnet, FTP, etc). The page will walk you through a step-by-step tutorial of creating a basic dissector for a made up HELLOWORLD protocol. This tutorial was based off of Xplico 0.7.1.

Writing The Dissector Module

Dissector modules are located in the “xplico-0.7.1\Dissectors” folder. Each dissector has a sub-directory within the Dissectors directory. For simplicity and convention, name the folder the name of the dissector. There are 3 files in this directory:

  • helloworld.c
  • helloworld.h
  • Makefile

helloworld.c

This is without a doubt the most difficult part of creating a dissector module. Most of the other code that is needed can usually be copied from another dissector module and tailored slightly to your new module without much understanding of how the Xplico Framework works behind the scenes. This is not the case with the helloworld.c file. This code not only contains the meat of your new dissector, but it also requires a much more intricate understanding of how Xplico works and interacts with dissector modules. Additionally, matters get further complicated by the fact that Xplico interacts differently based on the type of dissector module. In this tutorial, we are only going to focus on writing a dissector module for a protocol over TCP. The following methods are either required or highly recommended:

  • DissecRegist
    • The first function that gains execution within the HELLOWORLD dissector
    • This function must exist in the dissector module with this exact name
    • Registers the protocol information including: Name, Network Layer, Standard Port, Check Function, Verify Function, Dissector Function
    • Only gets called once when Xplico is initially started
  • DissectInit
    • The second function that gains execution within the HELLOWORLD dissector
    • This function must exist in the dissector module with this exact name
    • Initializes the HELLOWORLD dissector module
    • Only gets called once just prior to packets being sent to the dissector via Check and Verify calls
  • HelloworldCheck
    • Check gets called for every packet within every flow until a dissector returns TRUE
      • Once a dissector returns TRUE, the flow is identified as that particular protocol and Check does not get called for any other packets in that flow
    • This function is registered in the “DissectRegist” function
  • HelloworldVerify
    • Verify gets called for every packet within every flow that matches a certain criteria
      • Criteria is defined in the “DissectRegist” function under “dep”
      • e.g. Specific TCP port number
    • Works hand-in-hand with the Check function
      • If either one of the functions return TRUE, the flow is identified as a HELLOWORLD protocol
      • Once identified as a HELLOWORLD protocol, no other packets in the flow get checked or verified by any other protocol at the same network layer
    • Order: Each dissector's (in order of dissector) Verify method gets called (if criteria meets) for a specific packet
      • If no Verify method returns TRUE, then each dissector's (in order of dissector) Check method gets called for that packet
      • If no Verify or Check method returns TRUE, then the process is repeated for the next packet in the flow
      • Once a Verify or Check method returns TRUE, then no more packets in the flow get Checked or Verified and Xplico repeats the process with the next flow
  • HelloworldDissector
    • If a Verify or Check method returns TRUE then that means the flow was positively matched as a HELLOWORLD protocol and the HelloworldDissector function will be called
    • This function assumes that the flow is in fact a HELLOWORLD protocol flow
    • The purpose of this function is to strip out the interesting protocol data that we want to report

Notable Notes

  • TCP dissector provides in order and reliability
  • Protocol data may be split up into separate packets - this dissector does not account for that
/* helloworld.c
 * ...
 */

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <pcap.h>
#include <linux/tcp.h>

#include "proto.h"
#include "dmemory.h"
#include "etypes.h"
#include "flow.h"
#include "log.h"
#include "dnsdb.h"
#include "helloworld.h"
#include "pei.h"

#define HELLOWORLD_TMP_DIR    "helloworld"

/* info id */
static int ip_id;
static int ipv6_id;
static int ip_src_id;
static int ip_dst_id;
static int ipv6_src_id;
static int ipv6_dst_id;
static int tcp_id;
static int port_src_id;
static int port_dst_id;
static int lost_id;
static int helloworld_id;

/* pei id */
static int pei_msg_id;

static volatile unsigned int incr;


//This function assumes that the flow is in fact a helloworld flow
//  (due to the simple fact that the function is being called)
//Since the HELLOWORLD protocol is over TCP, the Xplico TCP dissector re-builds the
//  TCP stream for us and provides all of the packets in order to the HELLOWORLD 
//  dissector
static packet *HelloworldDissector(int flow_id)
{
	packet *pkt;
	const pstack_f *tcp, *ip;
	FILE *fp;
	pei *ppei;
	time_t cap_sec, end_cap;
	pei_component *cmpn;
	int count = 0;
	ftval ip_host, port;
	unsigned short port_num = 0;
	bool ipv6 = FALSE;

	char host[HELLOWORLD_HOST_NAME_SIZE] = {0};
	char msg[HELLOWORLD_MSG_BUF_SIZE] = {0};
	char cmd_file[HELLOWORLD_FILENAME_PATH_SIZE] = {0};

	printf("HelloworldDissector - Helloworld id: %d\n", flow_id);
	LogPrintf(LV_DEBUG, "HelloworldDissector1 - flow_id: %d", flow_id); 

	//open a file that we will write the protocol information that we want to report
	//	in this case we are just writing the 8 byte HELLOWORLD message to the file
	sprintf(cmd_file, "%s/%s/helloworld_%lu_%i.txt", ProtTmpDir(), HELLOWORLD_TMP_DIR, time(NULL), incr);
	incr++;
	fp = fopen(cmd_file, "w");

	//obtain tcp and ip structures corresponding to this flow
	tcp = FlowStack(flow_id); /* tcp frame */  
	ip = ProtGetNxtFrame(tcp); /* ip/ipv6 frame */

	//obtain the destination port number
	ProtGetAttr(tcp, port_dst_id, &port);
	port_num = port.uint16;

	//determine whether the flow is ipv4 or ipv6 and obtain the destination host/ip address
	if (ProtFrameProtocol(ip) == ipv6_id) {
		ipv6 = TRUE;
	}
	if (ipv6 == FALSE) {
		//ipv4
		ProtGetAttr(ip, ip_dst_id, &ip_host);
		if (DnsDbSearch(&(ip_host), FT_IPv4, host, HELLOWORLD_FILENAME_PATH_SIZE) != 0) {
			FTString(&(ip_host), FT_IPv4, host);
		}
	}
	else {
		//ipv6
		ProtGetAttr(ip, ipv6_dst_id, &ip_host);
		if (DnsDbSearch(&(ip_host), FT_IPv6, host, HELLOWORLD_FILENAME_PATH_SIZE) != 0) {
			FTString(&(ip_host), FT_IPv6, host);
		}
	}

	printf("HelloworldDissector - host:%s:%i - flow_id: %d\n", host, port_num, flow_id);
	LogPrintf(LV_DEBUG, "HelloworldDissector1.1 - host:%s:%i - flow_id: %d", host, port_num, flow_id);

	/* first packet */
	pkt = FlowGetPkt(flow_id);

	//This is a basic sanity check to make sure that the flow actually contains packets
	//  However, this function already assumes that this flow is in fact a helloworld flow due
	//  to the simple fact that this function was called.
	if (pkt != NULL) {	
		/* pei definition */
		PeiNew(&ppei, helloworld_id);
		PeiCapTime(ppei, pkt->cap_sec);
		PeiMarker(ppei, pkt->serial);
		PeiStackFlow(ppei, tcp);
		cap_sec = pkt->cap_sec;
	}

	//loop through all of the packets in the flow to dissect the helloworld protocol information
	//  this assumes that the entire 40 bytes of the helloworld protocol is contained in a single
	//  packet and not split between multiple packets.
	//  - There is no guerentee that the tcp/ip driver of the operating system sending the helloworld
	//    message will not split up the data into multiple packets.
	//  - However, in this case, since there are only 40 bytes of data it is highly likely that the
	//    data will not be split up into multiple packets.
	while (pkt != NULL) {
		count++;
		LogPrintf(LV_DEBUG, "HelloworldDissector2 - %i", count);
		
		//verify the packet is a HELLOWORLD packet
		if(pkt->len == 40) {
			//verify the start and end headers of the protocol
			if ( (strncmp(pkt->data, "helloworldstarts", 16) == 0) && (strncmp((pkt->data + 24), "helloworldending", 16) == 0) ) {
				
				printf("HelloworldDissector - FOUND A HELLOWORLD PROTOCOL MESSAGE\n");
				LogPrintf(LV_DEBUG, "HelloworldDissector3 - FOUND A HELLOWORLD PROTOCOL MESSAGE");
				
				strncpy(msg, (pkt->data + 16), 8);
				fwrite(msg, 1, 8, fp); //write the msg to the file

				//compose pei
				/* msg */
				PeiNewComponent(&cmpn, pei_msg_id);
				PeiCompCapTime(cmpn, pkt->cap_sec);
				PeiCompAddStingBuff(cmpn, msg);
				PeiCompAddFile(cmpn, "Helloworld Message", cmd_file, 8);
				PeiAddComponent(ppei, cmpn);

				//insert pei
				PeiIns(ppei);
				
				printf("HelloworldDissector inserted new message %s\n", msg);
				LogPrintf(LV_DEBUG, "HelloworldDissector4 inserted new message \"%s\"", msg);
				
				break;
			}
		}
	    
		//new/next packet within the flow
		PktFree(pkt);
		pkt = FlowGetPkt(flow_id);

	} //end while


	//close file
	if (fp != NULL) {
		fclose(fp);
	}

	printf("HelloworldDissector... bye bye\n");
	LogPrintf(LV_DEBUG, "HelloworldDissector5 - flow_id: %d", flow_id);

	return NULL;
}


//This is the worker function for both the Verify and Check routines.
//It gets called on a per-packet basis - the reason it loops calling "FlowGetPktCp", is because
//  there is no guerentee that all of the data for a valid HELLOWORLD packet is contained in the
//  same packet - it could be split up like so:
//    packet1: helloworldstartsmes
//    packet2: sage1helloworldending
static bool HelloworldVerifyCheck(int flow_id, bool check)
{
	packet *pkt;
	short cnt, cnt_lim;
	int count = 0;

	cnt = 0;
	pkt = FlowGetPktCp(flow_id);

	/* numer of packets to verify */
	cnt_lim = HELLOWORLD_PKT_CHECK_LIMIT;

	LogPrintf(LV_DEBUG, "HelloworldVerifyCheck1 - flow_id: %d", flow_id);

	if (!check) {
		//Verify
		LogPrintf(LV_DEBUG, "HelloworldVerifyCheck2 (verify) - flow_id: %d", flow_id);
		cnt_lim = 1;
		do {
			count++;
			LogPrintf(LV_DEBUG, "HelloworldVerifyCheck3 - flow_id: %d - %i", flow_id, count);
			while (pkt != NULL && pkt->len == 0) {
				PktFree(pkt);
				pkt = FlowGetPktCp(flow_id);
			}
			if (pkt != NULL && pkt->data != NULL && pkt->len != 0) {
				
				LogPrintf(LV_DEBUG, "HelloworldVerifyCheck4 - flow_id: %d - %i - len:%u - raw:%u", flow_id, count, pkt->len, pkt->raw_len);           
	            
				if (40 == pkt->len) {
					LogPrintf(LV_DEBUG, "HelloworldVerifyCheck5 - flow_id: %d - pktlen: %u", flow_id, pkt->len);
					cnt++;
				}
			}
			PktFree(pkt);
			pkt = FlowGetPktCp(flow_id);
		} while (pkt != NULL);
	}
	else {
		//Check
		LogPrintf(LV_DEBUG, "HelloworldVerifyCheck2 (check) - flow_id: %d", flow_id);
		do {
			count++;
			LogPrintf(LV_DEBUG, "HelloworldVerifyCheck3 - flow_id: %d - %i", flow_id, count);
			if (pkt != NULL && ((pkt->data != NULL && pkt->len != 0) || pkt->raw_len != 0) ) {

				//printf("helloworld.c - HelloworldVerifyCheck - flow_id: %d\n", flow_id);
				LogPrintf(LV_DEBUG, "HelloworldVerifyCheck4 - flow_id: %d - %i - len:%u - raw:%u", flow_id, count, pkt->len, pkt->raw_len);     
	            
				if (40 == pkt->len || 94 == pkt->raw_len) {
					LogPrintf(LV_DEBUG, "HelloworldVerifyCheck5 - flow_id: %d - pktlen: %u", flow_id, pkt->len);
					cnt++;
				}
				else {
					break;
				}
			}
			PktFree(pkt);
			pkt = FlowGetPktCp(flow_id);
		} while (pkt != NULL);
	}

	if (pkt != NULL)
		PktFree(pkt);
	if (cnt >= cnt_lim) {
		LogPrintf(LV_DEBUG, "HelloworldVerifyCheck6 - flow_id: %d - RETURN TRUE RETURN TRUE", flow_id;)
		return TRUE;
	}

	LogPrintf(LV_DEBUG, "HelloworldVerifyCheck6 - flow_id: %d", flow_id);
	return FALSE;
}


//Verify gets called for every packet within every flow that matches a certain criteria.
//  Specifically, any flow that has the certain TCP port number as specified in the
//  "DissectRegist" function under "dep"
//Works hand-in-hand with the Check function. If either one of the functions return TRUE,
//  then the flow is identified as a HELLOWORLD protocol and the Verify and Check functions
//  do not get called for any more packets in this flow.
//The first Dissector to "claim" a flow (by returning TRUE) gets it and no more Verify or 
//  Check functions get called on the flow from ANY dissector at the same Network Stack Layer.
//The Verify function gets called before the Check function
//Order: Each Dissectors Verify method (if criteria meets) in order of Dissector, then each
//  Dissectors Check function in order of Dissector
static bool HelloworldVerify(int flow_id)
{
	//printf("helloworld.c - HelloworldVerify - flow_id: %d\n", flow_id);
	LogPrintf(LV_DEBUG, "HelloworldVerify - flow_id: %d", flow_id);

	return HelloworldVerifyCheck(flow_id, FALSE);
}


//Check gets called for every packet within every flow until a dissector returns TRUE in
//  its Check function. Once a dissector returns TRUE, the flow is identified as that
//  particular protocol and Check does not get called for any other packets in that flow.
//  This is defined in the "DissectRegist" function under "hdep"
//Returning true in this function identifies the flow as a HELLOWORLD protocol and the
//  flow then gets passed to the HelloworldDissector function.
//Every Dissector Check function gets called - the first Dissector to return TRUE gets
//  the flow and no other Dissector at the same Network Stack Layer can also identify the
//  flow as their own.
static bool HelloworldCheck(int flow_id)
{
	//printf("helloworld.c - HelloworldCheck - flow_id: %d\n", flow_id);
	LogPrintf(LV_DEBUG, "HelloworldCheck - flow_id: %d", flow_id);

	return HelloworldVerifyCheck(flow_id, TRUE);
}


//This is the very first function that gains execution within the HELLOWORLD dissector
//Registers the HELLOWORLD dissector as a protocol on top of TCP and sets a Check,
//  Verify, and Dissector function for the protocol
//Defines the components of a HELLOWORLD protocol that will be identified ("msg")
//The name of this function must be "DissecRegist"
int DissecRegist(void)
{
	proto_heury_dep hdep;
	proto_dep dep;
	pei_cmpt peic;

	printf("Helloworld DissecRegist\n");
	LogPrintf(LV_DEBUG, "Helloworld - DissecRegist.");

	memset(&hdep, 0, sizeof(proto_heury_dep));
	memset(&dep, 0, sizeof(proto_dep));
	memset(&peic, 0, sizeof(pei_cmpt));

	/* protocol name */
	ProtName("Helloworld", "helloworld");

	/* hdep: tcp */
	hdep.name = "tcp";
	hdep.ProtCheck = HelloworldCheck;
	hdep.pktlim = HELLOWORLD_PKT_LIMIT;
	ProtHeuDep(&hdep);

	/* dep: tcp */
	dep.name = "tcp";
	dep.attr = "tcp.dstport";
	dep.type = FT_UINT16;
	dep.val.uint16 = TCP_PORT_HELLOWORLD;
	dep.ProtCheck = HelloworldVerify;
	dep.pktlim = HELLOWORLD_PKT_LIMIT;
	ProtDep(&dep);

	/* PEI components */
	peic.abbrev = "msg";
	peic.desc = "Message Sent";
	ProtPeiComponent(&peic);

	/* dissectors subdissectors registration */
	ProtDissectors(NULL, HelloworldDissector, NULL, NULL);

	return 0;
}


//Initializes HELLOWORLD dissector information
//The name of this function must be "DissectInit"
int DissectInit(void)
{
	char helloworld_dir[256];

	/* part of file name */
	incr = 0;

	printf("Helloworld DissectInit\n");
	LogPrintf(LV_DEBUG, "Helloworld - DissectInit.");

	/* info id */
	ip_id = ProtId("ip");
	ipv6_id = ProtId("ipv6");
	tcp_id = ProtId("tcp");
	ip_dst_id = ProtAttrId(ip_id, "ip.dst");
	ip_src_id = ProtAttrId(ip_id, "ip.src");
	ipv6_dst_id = ProtAttrId(ipv6_id, "ipv6.dst");
	ipv6_src_id = ProtAttrId(ipv6_id, "ipv6.src");
	port_dst_id = ProtAttrId(tcp_id, "tcp.dstport");
	port_src_id = ProtAttrId(tcp_id, "tcp.srcport");
	lost_id = ProtAttrId(tcp_id, "tcp.lost");
	helloworld_id = ProtId("helloworld");

	/* pei id */
	pei_msg_id = ProtPeiComptId(helloworld_id, "msg");

	/* helloworld tmp directory */
	sprintf(helloworld_dir, "%s/%s", ProtTmpDir(), HELLOWORLD_TMP_DIR);
	mkdir(helloworld_dir, 0x01FF);

	return 0;
}

helloworld.h

/* helloworld.h
 * ...
 */

#ifndef __HELLOWORLD_H__
#define __HELLOWORLD_H__

/* standard port */
#define TCP_PORT_HELLOWORLD				2233

#define HELLOWORLD_FILENAME_PATH_SIZE		        256
#define HELLOWORLD_HOST_NAME_SIZE			256

//The protocol only specifies an 8 byte message - so 16 bytes is excessive
//The database has a 16 byte varcar variable for the message
#define HELLOWORLD_MSG_BUF_SIZE				16

/* packets limit for HelloworldVerify, HelloworldCheck */
#define HELLOWORLD_PKT_LIMIT				10
#define HELLOWORLD_PKT_CHECK_LIMIT			1


#endif /* __HELLOWORLD_H__ */

Makefile

The Makefile can be easily created by copying a Makefile from a different Dissector Module and changing all of the instances of the other dissector's name with the name of your new dissector, helloworld.

# Makefile
# ...
#

# dissector name
DIS_NAME = dis_helloworld

# dissector library (.so)
DIS_SO = $(DIS_NAME).so

# sub directory
SUBDIRS = 

# src file
SRC = dis_log.c helloworld.c

# To make it visible
export CC CCPP ROOT_DIR CFLAGS LDFLAGS INCLUDE_DIR

all: subdir $(DIS_SO)

$(DIS_SO): $(SRC:.c=.o)
	$(CC) $(CFLAGS) -shared -Wl,-soname,$@ -o $@ $(SRC:.c=.o) $(LDFLAGS)

subdir:
	@for dir in $(SUBDIRS) ; \
	   do $(MAKE) -C $$dir || exit 1; \
	 done \

clean:
	@for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir clean || exit 1; done
	rm -f *.o *.so *~ include/*~ .depend *.expand

.depend: $(SRC)
	$(CC) -M $(CFLAGS) $(SRC) > $@

include ../Makefilelog
sinclude .depend

Integrating A Dissector Module Into Xplico

In addition to the main dissector module code that needs to be created (as shown above), other code needs to be added into existing Xplico source files. Many of these files can be easily modified by looking at another dissector and slightly tailoring it to your new one.

Required Modifications to Xplico Files

  • xplico-0.7.1\Dissectors\Makefile
  • xplico-0.7.1\dispatch\lite\lite.h
  • xplico-0.7.1\dispatch\lite\lite.c
  • xplico-0.7.1\dispatch\cli\cli.c
  • xplico-0.7.1\system\db\sqlite3\helloworlds.sql
  • xplico-0.7.1\system\db\sqlite3\create_xplico_db.sh

xplico-0.7.1\Dissectors\Makefile

Add helloworld into the SUBDIRS list

SUBDIRS += helloworld

xplico-0.7.1\dispatch\lite\lite.h

Add the helloworld directory path

#define XS_HELLOWORLD_DIR_PATH     XS_DB_INSTALL_DIR"/pol_%d/sol_%d/helloworld"

Add the helloworld database query template

#define XS_QUERY_HELLOWORLD_TEMPLATE "INSERT INTO helloworld (sol_id, pol_id, source_id, capture_date, flow_info, msg) VALUES (%i, %i, %i, "XPCAP_DATE", '%s', '%s')"

xplico-0.7.1\dispatch\lite\lite.c

Add helloworld static global variables (~line 276)

/* helloworld */
static int helloworld_id;
static int pei_helloworld_msg_id;

Implement a new function named DispHelloworld (~line 4588)

static int DispHelloworld(pei *ppei)
{

    pei_component *cmpn;
    char query[XS_QUERY_DIM];
    char rep[XS_QUERY_DIM];
    char flow_info[XS_STR_PATH];
	int pol, sess, src_id;
	const pstack_f *frame;
	ftval val, ip;
    char *msg;
    char *name;
	char *path; //path is the same as mfile from cli.c

	//printf("helloworld - lite.c - DispHelloworld\n");
	LogPrintf(LV_DEBUG, "Helloworld - lite.c - DispHelloworld1");

    /* search pol and session */
    frame = ProtStackSearchProt(ppei->stack, pol_id);
    if (frame) {
        ProtGetAttr(frame, pol_polid_id, &val);
        pol = val.int32;
        ProtGetAttr(frame, pol_sesid_id, &val);
        sess = val.int32;
    }
    else {
        sess = pol = 1;
    }
    /* search source ip */
    src_id = -1;
    frame = ProtStackSearchProt(ppei->stack, ip_id);
    if (frame) {
        ProtGetAttr(frame, ip_src_id, &ip);
        src_id = DispHostSrch(&ip, FT_IPv4);
        if (src_id == -1) {
            /* search in db */
            FTString(&ip, FT_IPv4, flow_info);
            src_id = DispHostDb(flow_info, pol, sess);
            if (src_id == -1) {
                query[0] = '\0';
                /* insert record */
                DnsDbSearch(&ip, FT_IPv4, query, XS_QUERY_DIM);
                src_id = DispHostDbIns(flow_info, query, pol, sess);
            }
            DispHostIns(&ip, FT_IPv4, src_id);
        }
    }
    else if (ipv6_id != -1) {
        frame = ProtStackSearchProt(ppei->stack, ipv6_id);
        if (frame) {
            ProtGetAttr(frame, ipv6_src_id, &ip);
            src_id = DispHostSrch(&ip, FT_IPv6);
            if (src_id == -1) {
                /* search in db */
                FTString(&ip, FT_IPv6, flow_info);
                src_id = DispHostDb(flow_info, pol, sess);
                if (src_id == -1) {
                    query[0] = '\0';
                    /* insert record */
                    DnsDbSearch(&ip, FT_IPv6, query, XS_QUERY_DIM);
                    src_id = DispHostDbIns(flow_info, query, pol, sess);
                }
                DispHostIns(&ip, FT_IPv6, src_id);
            }
        }
    }

    msg = NULL;
	path = NULL;
    cmpn = ppei->components;
    while (cmpn != NULL) {
		if (cmpn->eid == pei_helloworld_msg_id) {
            msg = cmpn->strbuf;
			path = cmpn->file_path;
        }
        cmpn = cmpn->next;
    }

	LogPrintf(LV_DEBUG, "Helloworld - lite.c - DispHelloworld2");

    /* compose query and insert record */
    if (path) {
		LogPrintf(LV_DEBUG, "Helloworld - lite.c - path:%s - DispHelloworld3", path);
        /* new path */
        name = strrchr(path, '/');
        name++;
        sprintf(rep, XS_HELLOWORLD_DIR_PATH"/%s", pol, sess, name);
        rename(path, rep);
        DispFilePaths(pol, rep);
        /* flow info */
        sprintf(flow_info, XS_HELLOWORLD_DIR_PATH"/flow_%s.xml", pol, sess, name);
        DispFlowInfo(flow_info, ppei->stack);
        /* query */
        sprintf(query, XS_QUERY_HELLOWORLD_TEMPLATE, sess, pol, src_id, PEI_TIME(ppei->time_cap), flow_info, msg);
        if (DispQuery(query, NULL) != 0) {
            printf("query: %s\n", query);
			LogPrintf(LV_DEBUG, "Helloworld - lite.c - query:%s - DispHelloworld4", query);
        }
    }

    return 0;
}

Add helloworld code into DispInit function (~line 5008)

    helloworld_id = ProtId("helloworld");
    if (helloworld_id != -1) {
        pei_helloworld_msg_id = ProtPeiComptId(helloworld_id, "msg");
    }

Add helloworld code into DispInsPei function (~line 5147)

        else if (ppei->prot_id == helloworld_id) {
            ret = DispHelloworld(ppei);
        }

xplico-0.7.1\dispatch\cli\cli.c

Add static global variables for helloworld (~line 262)

/* helloworld */
static int helloworld_id;
static int pei_helloworld_msg_id;
static unsigned long npop, nsmtp, nimap, nhttp, nftp, nipp,
    npjl, nmms, ntftp, ndns, nnntp, nfbwc, ntelnet, nwebmail,
    nhttpfile, ngrptcp, ngrpudp, nrtp, nsip, narp, nirc, npltk_exp,
    npltk, msn, nbo, mgcp, webmsn, syslog, helloworld;

Implement a new function named DispDirHelloworld (~line 450)

static inline int DispDirHelloworld(char *src, char *msg)
{
    char dir[XCLI_STR_DIM];

	//printf("helloworld - cli.c - DispDirHelloworld\n");
	LogPrintf(LV_DEBUG, "Helloworld - cli.c - msg:%s - DispDirHelloworld", msg);

    sprintf(dir, "%s/%s", xdecode, src);
    mkdir(dir, 0x01FF);
    sprintf(dir, "%s/%s/helloworld/", xdecode, src);
    mkdir(dir, 0x01FF);
    sprintf(dir, "%s/%s/helloworld/%s", xdecode, src, msg);
    mkdir(dir, 0x01FF);
    
    return 0;
}

Implement a new function named DispHelloworld (~line 2345)

static int DispHelloworld(pei *ppei)
{
    pei_component *cmpn;
    char new_path[XCLI_STR_DIM];
    char ip_src[XCLI_STR_DIM];
    char *name;
    char *msg, *mfile;

	//printf("helloworld - cli.c - DispHelloworld\n");
	LogPrintf(LV_DEBUG, "Helloworld - cli.c - DispHelloworld1");

    msg = NULL;
    cmpn = ppei->components;
    
	while (cmpn != NULL) {
        if (cmpn->eid == pei_helloworld_msg_id) {
            msg = cmpn->strbuf;
			mfile = cmpn->file_path;
        }
        cmpn = cmpn->next;
    }

	if (msg != NULL) {
		LogPrintf(LV_DEBUG, "Helloworld - cli.c - msg:%s - DispHelloworld2", msg);
        /* dir name and creation */
        if (DispIp(ppei->stack, ip_src) == NULL)
            return -1;
        DispDirHelloworld(ip_src, msg);
        
		if (mfile == NULL) {
			printf("helloworld - mfile is NULL - error\n");
		}
		printf("Message: %s, filepath: %s\n", msg, mfile);

        name = strrchr(mfile, '/');
        name++;
        sprintf(new_path, "%s/%s/helloworld/%s/%s", xdecode, ip_src, msg, name);
        rename(mfile, new_path);
        DispFilePaths(new_path);
    }

	LogPrintf(LV_DEBUG, "Helloworld - cli.c - DispHelloworld3");

    return 0;       
}

Add code to the DispInit function (~line 2412)

helloworld = 0;
    helloworld_id = ProtId("helloworld");
    if (helloworld_id != -1) {
        pei_helloworld_msg_id = ProtPeiComptId(helloworld_id, "msg");
    }

Add code to the DispEnd function (~line 2755)

printf("\thelloworld: %lu\n", helloworld);

Add code to the DispInsPei function (~line 2914)

    else if (ppei->prot_id == helloworld_id) {
		if (ppei->ret == FALSE)
			helloworld++;
        ret = DispHelloworld(ppei);
    }

xplico-0.7.1\system\db\sqlite3\helloworlds.sql

This file needs to be created. It should correspond with the query template definition (XS_QUERY_HELLOWORLD_TEMPLATE) added in “lite.h”

--
-- Tabella delle connessioni helloworld
--
CREATE TABLE IF NOT EXISTS helloworlds (
  id INTEGER NOT NULL PRIMARY KEY,
  sol_id INT( 10 ) NOT NULL REFERENCES sols(id) ON DELETE CASCADE ON UPDATE CASCADE,
  pol_id INT( 10 ) NOT NULL REFERENCES pols(id) ON DELETE CASCADE ON UPDATE CASCADE,
  source_id INT( 10 ) NOT NULL REFERENCES sources(id) ON DELETE CASCADE ON UPDATE CASCADE,
  capture_date TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
  decoding_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  viewed_date TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
  first_visualization_user_id INT( 10 ) NOT NULL DEFAULT '0',
  flow_info VARCHAR( 255 ) NOT NULL,
  msg VARCHAR( 16 )
);

xplico-0.7.1\system\db\sqlite3\create_xplico_db.sh

Add the following code to this file:

sqlite3 $DIR_BASE/xplico.db < helloworlds.sql

Optional Modifications to Xplico Files

  • xplico-0.7.1\l7-patternshelloworld.pat
  • xplico-0.7.1\dispatch\gearth.c

Building Xplico from Source and Running Xplico

  • Step by Step Xplico 0.7.0 and 0.7.1 Installation
  • Enable the new dissector by adding it into the corresponding configuration file
  • Run Xplico as shown below

Add to corresponding config file in “/opt/xplico/cfg” (see Run Xplico)

MODULE=dis_helloworld.so     LOG=FEWITDS

Run Xplico

Run Xplico with web interface
Note: uses xplico_install_lite.cfg config file by default

/opt/xplico/script/sqlite_demo.sh

Run Xplico via the command line (cli)
Note: uses xplico_cli.cfg config file by default

cd /opt/xplico/bin
./xplico -m pcap -f /path/to/pcap/helloworld_dump.pcap

Run Xplico via the command line (cli) - with checksum verification disabled
Note: This may be necessary depending on how you captured your network dump
http://wiki.wireshark.org/CaptureSetup/Offloading

cd /opt/xplico/bin
./xplico -c ../cfg/xplico_cli_nc.cfg -m pcap -f /path/to/pcap/helloworld_dump.pcap

Adding Enhancements to the Dissector Module

There are several things that this basic dissector module does not account for in order to make it less complex. This section discusses more advanced concepts for creating robust and production-ready dissectors.

  • Protocol data split into multiple packets
  • Lost packets
  • Playing nice with other dissectors
  • Creating a .PAT file for regular expression
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution 4.0 International
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki