Ethereal-dev: [ethereal-dev] ICQ dissector

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

From: Kojak <kojak@xxxxxxxxxx>
Date: Fri, 24 Dec 1999 15:57:01 +0100
Hi

I added the routines to dynamically set the correct TCP portnumbers to the 
icq-tcp dissector. However, the current implementation doesn't quite work.

The display filter is compiled ok, but the dissector is not called. Currently
I don't have a clue why.

Here's the code at least, so others can comment on the chosen method, which
boils down to: "keep a list of portnumbers, if one is added, generate a 
new filter string, recompile the filter and install".

Grtz
Kojak

Index: packet-icq.c
===================================================================
RCS file: /cvsroot/ethereal/packet-icq.c,v
retrieving revision 1.9
diff -u -r1.9 packet-icq.c
--- packet-icq.c	1999/12/05 22:59:55	1.9
+++ packet-icq.c	1999/12/24 14:49:09
@@ -67,6 +67,10 @@
 
 #include "packet.h"
 #include "resolv.h"
+#include "globals.h"
+#include "plugins.h"
+#include "dfilter.h"
+#include "ui_util.h"
 
 static int proto_icq = -1;
 static int hf_icq_uin =-1;
@@ -84,11 +88,20 @@
 
 enum { ICQ5_client, ICQ5_server};
 
+static gchar Dissect_TCP_ICQ_Version[]="tcp dissect 0.0.1";
+static gchar Dissect_TCP_ICQ_Name[]="tcp dissect 0.0.1";
+static GList* watchList = NULL;
+
 void dissect_icqv5(const u_char *pd,
 		   int offset,
 		   frame_data *fd,
 		   proto_tree *tree);
 
+void dissect_icq_chat(const u_char *pd,
+		      int offset,
+		      frame_data *fd,
+		      proto_tree *tree);
+
 static void
 dissect_icqv5Server(const u_char *pd,
 		    int offset,
@@ -386,7 +399,118 @@
  0x3B, 0x4D, 0x46, 0x68, 0x63, 0x39, 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x67, 0x53, 0x41, 0x25, 0x41,
  0x3C, 0x51, 0x54, 0x3D, 0x5E, 0x54, 0x5D, 0x4E, 0x4C, 0x39, 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F,
  0x47, 0x43, 0x69, 0x48, 0x33, 0x51, 0x54, 0x5D, 0x6E, 0x3C, 0x31, 0x64, 0x35, 0x5A, 0x00, 0x00 };
- 
+
+static void
+generateFilter(GList* list)
+{
+    int n = 0;
+    int i = 0;
+    int res = 0;
+    int size = 0;
+    char* buf = NULL;
+    GList* iptr = NULL;
+    n = g_list_length(list);
+    size = n * sizeof("tcp.port==xxxxx ||");
+    buf = g_malloc(size);
+    i = 0;
+    for ( iptr=g_list_first(list);
+	  iptr!=NULL;
+	  iptr=g_list_next(iptr)) {
+	fprintf(stderr,"ICQ: Port = %d\n", GPOINTER_TO_INT(iptr->data));
+	if (i==0) {
+	    res = snprintf(buf+i,size - i,"tcp.port==%d", GPOINTER_TO_INT(iptr->data));
+	} else {
+	    res = snprintf(buf+i,size - i,"|| tcp.port==%d", GPOINTER_TO_INT(iptr->data));
+	}
+	i += res;
+    }
+    fprintf(stderr,"ICQ: Setting filter %d ports \"%s\"\n", n, buf);
+    if (n>0) {
+	dfilter* df = NULL;
+	if (dfilter_compile(buf, &df)==0) {
+	    plugin_replace_filter(Dissect_TCP_ICQ_Name,
+				  Dissect_TCP_ICQ_Version,
+				  buf,
+				  df);
+	    enable_plugin(Dissect_TCP_ICQ_Name,
+			  Dissect_TCP_ICQ_Version);
+	} else {
+	    simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
+	}
+    } else {
+	disable_plugin(Dissect_TCP_ICQ_Name,
+		       Dissect_TCP_ICQ_Version);
+    }
+    g_free(buf);
+}
+
+/*
+ * Adds a new tcp port to the list to be watched. This is for the time
+ * being, until there is a more elegant way to do this
+ */
+static GList* 
+addWatchTCPPort(GList* list, guint16 port)
+{
+    fprintf(stderr, "ICQ: watchList[%d]\n", g_list_length(list));
+    if (g_list_index(list, GINT_TO_POINTER(port))==-1) {
+	list = g_list_append(list, GINT_TO_POINTER((guint32)port));
+	fprintf(stderr, "ICQ: watchList[%d]\n", g_list_length(list));
+	generateFilter(list);
+    }
+    return list;
+}
+
+/*
+ * delete the named port from the watchlist
+ */
+static GList*
+deleteWatchTCPPort(GList* list, guint16 port)
+{
+    list = g_list_remove(list, GINT_TO_POINTER((guint32)port));
+    generateFilter(list);
+    return list;
+}
+
+/*
+ * Initialize the structure, and set the filters to a proper value
+ */
+static int
+initWatchList(GList* list,
+	      void (*dissector) (const u_char *, int, frame_data *, proto_tree *))
+{
+    /* list is not used, but inserted to be able to maybe change the
+     * implementation later on.
+     */
+    int res;
+    res = add_plugin(NULL,	/* This is not from a dynamic thing */
+		     Dissect_TCP_ICQ_Name,
+		     Dissect_TCP_ICQ_Version,
+		     "tcp",
+		     NULL,	/* Do not add a filter right now */
+		     NULL,	/* Can you pass a NULL compiled filter */
+		     dissector);
+    disable_plugin(Dissect_TCP_ICQ_Name, Dissect_TCP_ICQ_Version);
+    return (res);
+}
+
+/*
+ * Delete all the ports from the filter, and destroy the
+ * list itself.
+ */
+static void
+deleteWatchList(GList* list)
+{
+    plugin_replace_filter(Dissect_TCP_ICQ_Name,
+			  Dissect_TCP_ICQ_Version,
+			  NULL,
+			  NULL);                 /* Legal to pass non-compiled string? */
+    disable_plugin(Dissect_TCP_ICQ_Name, Dissect_TCP_ICQ_Version);
+    g_list_free(list);
+}
+
+/*
+ * Find a cmdcode in the map between a code and its description.
+ */
 static char*
 findcmd(cmdcode* c, int num)
 {
@@ -1197,6 +1321,7 @@
     }
     if (left>=8) {
 	port = pletohl(pd + CMD_LOGIN_PORT);
+	watchList = addWatchTCPPort(watchList, port);
     }
     if (left>=10) {
 	passwdLen = pletohs(pd + CMD_LOGIN_PASSLEN);
@@ -1405,8 +1530,10 @@
     if (size >= SRV_USER_ONL_IP + 4) 
 	ipAddrp = &pd[SRV_USER_ONL_IP];
 
-    if (size >= SRV_USER_ONL_PORT + 4)
+    if (size >= SRV_USER_ONL_PORT + 4) {
 	port = pletohl(pd + SRV_USER_ONL_PORT);
+	watchList = addWatchTCPPort(watchList, port);
+    }
 
     if (size >= SRV_USER_ONL_REALIP + 4)
 	realipAddrp = &pd[SRV_USER_ONL_REALIP];
@@ -1545,6 +1672,7 @@
 {
 #if 0
     proto_tree* subtree = NULL;
+    proto_tree* sstree = NULL;
 #endif
     proto_tree* sstree = NULL;
     proto_item* ti = NULL;
@@ -1897,6 +2025,11 @@
     guint16 tcpVer;
     int left = size;
     
+    if (left >= SRV_RAND_USER_PORT + sizeof(guint32)) {
+	fprintf("ICQ: Adding a port (tree = %p)\n", tree);
+	port = pletohs(pd + SRV_RAND_USER_PORT);
+	watchList = addWatchTCPPort(watchList, port);
+    }
     if (tree) {
 	ti = proto_tree_add_item_format(tree,
 					hf_icq_cmd,
@@ -1927,6 +2060,7 @@
 	if (left<sizeof(guint32))
 	    return;
 	port = pletohs(pd + SRV_RAND_USER_PORT);
+	watchList = addWatchTCPPort(watchList, port);
 	proto_tree_add_text(subtree,
 			    offset + SRV_RAND_USER_UIN,
 			    sizeof(guint32),
@@ -1988,7 +2122,7 @@
     guint16 seqnum1 = 0 , seqnum2 = 0;
     guint32 uin = -1, sessionid = -1;
     guint32 key = -1;
-    guint16 pktsize = -1;	/* The size of the ICQ content */
+    guint16 pktsize = -1;  /* The size of the ICQ content */
     u_char decr_pd[1600];	/* Decrypted content, size should be dynamic */
     
     pktsize = fd->pkt_len - offset;
@@ -2059,80 +2193,82 @@
 			    offset + ICQ5_CL_SEQNUM1,
 			    2,
 			    "Seqnum2: 0x%04x", seqnum2);
-	switch(cmd) {
-	case CMD_ACK:
-	    icqv5_cmd_ack(icq_tree,
-			  decr_pd + ICQ5_CL_HDRSIZE,
-			  offset + ICQ5_CL_HDRSIZE,
-			  pktsize - ICQ5_CL_HDRSIZE);
-	    break;
-	case CMD_SEND_MSG:
-	case CMD_MSG_TO_NEW_USER:
-	    icqv5_cmd_send_msg(icq_tree,
-			       decr_pd + ICQ5_CL_HDRSIZE,
-			       offset + ICQ5_CL_HDRSIZE,
-			       pktsize - ICQ5_CL_HDRSIZE,
-			       cmd);
-	    break;
-	case CMD_RAND_SEARCH:
-	    icqv5_cmd_rand_search(icq_tree,
-				  decr_pd + ICQ5_CL_HDRSIZE,
-				  offset + ICQ5_CL_HDRSIZE,
-				  pktsize - ICQ5_CL_HDRSIZE);
-	    break;
+    }
+    switch(cmd) {
+    case CMD_ACK:
+	icqv5_cmd_ack(icq_tree,
+		      decr_pd + ICQ5_CL_HDRSIZE,
+		      offset + ICQ5_CL_HDRSIZE,
+		      pktsize - ICQ5_CL_HDRSIZE);
+	break;
+    case CMD_SEND_MSG:
+    case CMD_MSG_TO_NEW_USER:
+	icqv5_cmd_send_msg(icq_tree,
+			   decr_pd + ICQ5_CL_HDRSIZE,
+			   offset + ICQ5_CL_HDRSIZE,
+			   pktsize - ICQ5_CL_HDRSIZE,
+			   cmd);
+	break;
+    case CMD_RAND_SEARCH:
+	icqv5_cmd_rand_search(icq_tree,
+			      decr_pd + ICQ5_CL_HDRSIZE,
+			      offset + ICQ5_CL_HDRSIZE,
+			      pktsize - ICQ5_CL_HDRSIZE);
+	break;
 	case CMD_LOGIN:
 	    icqv5_cmd_login(icq_tree,
 			    decr_pd + ICQ5_CL_HDRSIZE,
 			    offset + ICQ5_CL_HDRSIZE,
 			    pktsize - ICQ5_CL_HDRSIZE);
-	    break;
-	case CMD_SEND_TEXT_CODE:
-	    icqv5_cmd_send_text_code(icq_tree,
-				     decr_pd + ICQ5_CL_HDRSIZE,
-				     offset + ICQ5_CL_HDRSIZE,
-				     pktsize - ICQ5_CL_HDRSIZE);
-	    break;
-	case CMD_STATUS_CHANGE:
-	    icqv5_cmd_status_change(icq_tree,
-				    decr_pd + ICQ5_CL_HDRSIZE,
-				    offset + ICQ5_CL_HDRSIZE,
-				    pktsize - ICQ5_CL_HDRSIZE);
 	    break;
-	case CMD_ACK_MESSAGES:
-	    icqv5_cmd_ack_messages(icq_tree,
-				   decr_pd + ICQ5_CL_HDRSIZE,
-				   offset + ICQ5_CL_HDRSIZE,
-				   pktsize - ICQ5_CL_HDRSIZE);
-	    break;
-	case CMD_KEEP_ALIVE:
-	    icqv5_cmd_keep_alive(icq_tree,
+    case CMD_SEND_TEXT_CODE:
+	icqv5_cmd_send_text_code(icq_tree,
 				 decr_pd + ICQ5_CL_HDRSIZE,
 				 offset + ICQ5_CL_HDRSIZE,
 				 pktsize - ICQ5_CL_HDRSIZE);
-	    break;
-	case CMD_ADD_TO_LIST:
-	    icqv5_cmd_add_to_list(icq_tree,
-				   decr_pd + ICQ5_CL_HDRSIZE,
-				   offset + ICQ5_CL_HDRSIZE,
-				   pktsize - ICQ5_CL_HDRSIZE);
-	    break;
-	case CMD_CONTACT_LIST:
-	    icqv5_cmd_contact_list(icq_tree,
-				   decr_pd + ICQ5_CL_HDRSIZE,
-				   offset + ICQ5_CL_HDRSIZE,
-				   pktsize - ICQ5_CL_HDRSIZE);
-	    break;
-	case CMD_META_USER:
-	case CMD_REG_NEW_USER:
-	case CMD_QUERY_SERVERS:
-	case CMD_QUERY_ADDONS:
-	    icqv5_cmd_no_params(icq_tree,
+	break;
+    case CMD_STATUS_CHANGE:
+	icqv5_cmd_status_change(icq_tree,
 				decr_pd + ICQ5_CL_HDRSIZE,
 				offset + ICQ5_CL_HDRSIZE,
-				pktsize - ICQ5_CL_HDRSIZE,
-				cmd);
-	    break;
-	default:
+				pktsize - ICQ5_CL_HDRSIZE);
+	break;
+    case CMD_ACK_MESSAGES:
+	icqv5_cmd_ack_messages(icq_tree,
+			       decr_pd + ICQ5_CL_HDRSIZE,
+			       offset + ICQ5_CL_HDRSIZE,
+			       pktsize - ICQ5_CL_HDRSIZE);
+	break;
+    case CMD_KEEP_ALIVE:
+	icqv5_cmd_keep_alive(icq_tree,
+			     decr_pd + ICQ5_CL_HDRSIZE,
+			     offset + ICQ5_CL_HDRSIZE,
+			     pktsize - ICQ5_CL_HDRSIZE);
+	break;
+    case CMD_ADD_TO_LIST:
+	icqv5_cmd_add_to_list(icq_tree,
+			      decr_pd + ICQ5_CL_HDRSIZE,
+			      offset + ICQ5_CL_HDRSIZE,
+			      pktsize - ICQ5_CL_HDRSIZE);
+	break;
+    case CMD_CONTACT_LIST:
+	icqv5_cmd_contact_list(icq_tree,
+			       decr_pd + ICQ5_CL_HDRSIZE,
+			       offset + ICQ5_CL_HDRSIZE,
+			       pktsize - ICQ5_CL_HDRSIZE);
+	break;
+    case CMD_META_USER:
+    case CMD_REG_NEW_USER:
+    case CMD_QUERY_SERVERS:
+    case CMD_QUERY_ADDONS:
+	icqv5_cmd_no_params(icq_tree,
+			    decr_pd + ICQ5_CL_HDRSIZE,
+			    offset + ICQ5_CL_HDRSIZE,
+			    pktsize - ICQ5_CL_HDRSIZE,
+			    cmd);
+	break;
+    default:
+	if (tree)
 	    proto_tree_add_item_format(icq_tree,
 				       hf_icq_cmd,
 				       offset+ICQ5_CL_CMD,
@@ -2140,9 +2276,10 @@
 				       cmd,
 				       "Command: %d (%s)",
 				       cmd, findClientCmd(cmd));
-	    fprintf(stderr,"Missing: %s\n", findClientCmd(cmd));
-	    break;
-	}
+	fprintf(stderr,"Missing: %s\n", findClientCmd(cmd));
+	break;
+    }
+    if (tree) {
 	ti = proto_tree_add_text(icq_tree,
 				 offset,
 				 pktsize,
@@ -2150,7 +2287,6 @@
         icq_decode_tree = proto_item_add_subtree(ti,
 						 ett_icq_decode);
 	proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
-
     }
 }
 
@@ -2238,87 +2374,89 @@
 				   checkcode,
 				   "Checkcode: 0x%08x",
 				   checkcode);
-	switch (cmd) {
-	case SRV_RAND_USER:
-	    icqv5_srv_rand_user(icq_tree,
-			       decr_pd + ICQ5_SRV_HDRSIZE,
-			       offset + ICQ5_SRV_HDRSIZE,
-			       pktsize - ICQ5_SRV_HDRSIZE);
-	    break;
-	case SRV_SYS_DELIVERED_MESS:
-	    /* The message structures are all the same. Why not run
-	     * the same routine? */
-	    icqv5_cmd_send_msg(icq_tree,
-			       decr_pd + ICQ5_SRV_HDRSIZE,
-			       offset + ICQ5_SRV_HDRSIZE,
-			       pktsize - ICQ5_SRV_HDRSIZE,
-			       cmd);
-	    break;
-	case SRV_USER_ONLINE:
-	    icqv5_srv_user_online(icq_tree,
-			       decr_pd + ICQ5_SRV_HDRSIZE,
-			       offset + ICQ5_SRV_HDRSIZE,
-			       pktsize - ICQ5_SRV_HDRSIZE);
-	    break;
-	case SRV_USER_OFFLINE:
-	    icqv5_srv_user_offline(icq_tree,
-			       decr_pd + ICQ5_SRV_HDRSIZE,
-			       offset + ICQ5_SRV_HDRSIZE,
-			       pktsize - ICQ5_SRV_HDRSIZE);
-	    break;
-	case SRV_LOGIN_REPLY:
-	    icqv5_srv_login_reply(icq_tree,
+    }
+    switch (cmd) {
+    case SRV_RAND_USER:
+	icqv5_srv_rand_user(icq_tree,
+			    decr_pd + ICQ5_SRV_HDRSIZE,
+			    offset + ICQ5_SRV_HDRSIZE,
+			    pktsize - ICQ5_SRV_HDRSIZE);
+	break;
+    case SRV_SYS_DELIVERED_MESS:
+	/* The message structures are all the same. Why not run
+	 * the same routine? */
+	icqv5_cmd_send_msg(icq_tree,
+			   decr_pd + ICQ5_SRV_HDRSIZE,
+			   offset + ICQ5_SRV_HDRSIZE,
+			   pktsize - ICQ5_SRV_HDRSIZE,
+			   cmd);
+	break;
+    case SRV_USER_ONLINE:
+	icqv5_srv_user_online(icq_tree,
+			      decr_pd + ICQ5_SRV_HDRSIZE,
+			      offset + ICQ5_SRV_HDRSIZE,
+			      pktsize - ICQ5_SRV_HDRSIZE);
+	break;
+    case SRV_USER_OFFLINE:
+	icqv5_srv_user_offline(icq_tree,
 			       decr_pd + ICQ5_SRV_HDRSIZE,
 			       offset + ICQ5_SRV_HDRSIZE,
 			       pktsize - ICQ5_SRV_HDRSIZE);
-	    break;
-	case SRV_META_USER:
-	    icqv5_srv_meta_user(icq_tree,
+	break;
+    case SRV_LOGIN_REPLY:
+	icqv5_srv_login_reply(icq_tree,
+			      decr_pd + ICQ5_SRV_HDRSIZE,
+			      offset + ICQ5_SRV_HDRSIZE,
+			      pktsize - ICQ5_SRV_HDRSIZE);
+	break;
+    case SRV_META_USER:
+	icqv5_srv_meta_user(icq_tree,
+			    decr_pd + ICQ5_SRV_HDRSIZE,
+			    offset + ICQ5_SRV_HDRSIZE,
+			    pktsize - ICQ5_SRV_HDRSIZE);
+	break;
+    case SRV_RECV_MESSAGE:
+	icqv5_srv_recv_message(icq_tree,
 			       decr_pd + ICQ5_SRV_HDRSIZE,
 			       offset + ICQ5_SRV_HDRSIZE,
 			       pktsize - ICQ5_SRV_HDRSIZE);
-	    break;
-	case SRV_RECV_MESSAGE:
-	    icqv5_srv_recv_message(icq_tree,
-				   decr_pd + ICQ5_SRV_HDRSIZE,
-				   offset + ICQ5_SRV_HDRSIZE,
-				   pktsize - ICQ5_SRV_HDRSIZE);
-	    break;
-	case SRV_MULTI:
-	    icqv5_srv_multi(icq_tree,
+	break;
+    case SRV_MULTI:
+	icqv5_srv_multi(icq_tree,
+			decr_pd + ICQ5_SRV_HDRSIZE,
+			offset + ICQ5_SRV_HDRSIZE,
+			pktsize - ICQ5_SRV_HDRSIZE,
+			fd);
+	break;
+    case SRV_ACK:
+    case SRV_GO_AWAY:
+    case SRV_NEW_UIN:
+    case SRV_BAD_PASS:
+    case SRV_UPDATE_SUCCESS:
+	icqv5_srv_no_params(icq_tree,
 			    decr_pd + ICQ5_SRV_HDRSIZE,
 			    offset + ICQ5_SRV_HDRSIZE,
 			    pktsize - ICQ5_SRV_HDRSIZE,
-			    fd);
-	    break;
-	case SRV_ACK:
-	case SRV_GO_AWAY:
-	case SRV_NEW_UIN:
-	case SRV_BAD_PASS:
-	case SRV_UPDATE_SUCCESS:
-	    icqv5_srv_no_params(icq_tree,
-				decr_pd + ICQ5_SRV_HDRSIZE,
-				offset + ICQ5_SRV_HDRSIZE,
-				pktsize - ICQ5_SRV_HDRSIZE,
-				cmd);
-	    break;
-	default:
-	    proto_tree_add_item_format(icq_tree,
-				       hf_icq_cmd,
-				       offset + ICQ5_SRV_CMD,
-				       2,
-				       cmd,
-				       "Command: %d (%s)",
-				       cmd, findServerCmd(cmd));
-	    fprintf(stderr,"Missing: %s\n", findServerCmd(cmd));
-	    break;
-	}
-
+			    cmd);
+	break;
+    default:
+	proto_tree_add_item_format(icq_tree,
+				   hf_icq_cmd,
+				   offset + ICQ5_SRV_CMD,
+				   2,
+				   cmd,
+				   "Command: %d (%s)",
+				   cmd, findServerCmd(cmd));
+	fprintf(stderr,"Missing: %s\n", findServerCmd(cmd));
+	break;
+    }
+    
+    if (tree) {
 	ti = proto_tree_add_text(icq_tree,
 				 offset,
 				 pktsize,
 				 "Decoded packet");
-        icq_decode_tree = proto_item_add_subtree(ti,
+	icq_decode_tree = proto_item_add_subtree(ti,
 						 ett_icq_decode);
 	proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
     }
@@ -2342,6 +2480,16 @@
   }
 }
 
+void dissect_icq_chat(const u_char *pd,
+		      int offset,
+		      frame_data *fd,
+		      proto_tree *tree)
+{
+    fprintf(stderr, "Dissect ICQ Chat\n");
+    if (check_col(fd, COL_PROTOCOL))
+	col_add_str(fd, COL_PROTOCOL, "ICQ chat");
+}
+
 void dissect_icq(const u_char *pd,
 		 int offset,
 		 frame_data *fd, 
@@ -2394,4 +2542,19 @@
     proto_register_field_array(proto_icq, hf, array_length(hf));
 
     proto_register_subtree_array(ett, array_length(ett));
+}
+
+/*
+ * This routine is called when a new file is opened, or when a new
+ * pass is made through the capture.
+ */
+void
+icq_init_protocol()
+{
+    /* Clear all filters available
+     * so the dissector can start with a clean repsheat.
+     */
+    deleteWatchList(watchList);
+    watchList = NULL;		/* It has been removed by deleteWatchList */
+    initWatchList(watchList, dissect_icq_chat);
 }