Ethereal-dev: [ethereal-dev] Packet-icq update

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

From: Kojak <kojak@xxxxxxxxxx>
Date: Mon, 25 Oct 1999 21:32:28 +0200
Hi,

A patch to the ICQ code. It's far from finished, but the login packets
are displayed ok, as are the text messages.

Kojak


Index: packet-icq.c
===================================================================
RCS file: /cvsroot/ethereal/packet-icq.c,v
retrieving revision 1.1
diff -r1.1 packet-icq.c
46a47,50
> #ifdef HAVE_ARPA_INET_H
> #include <arpa/inet.h>
> #endif
> 
50a55
> #include <string.h>
123a129,189
> #define MSG_TEXT		0x0001
> #define MSG_URL			0x0004
> #define MSG_AUTH_REQ		0x0006
> #define MSG_AUTH		0x0008
> #define MSG_USER_ADDED		0x000c
> #define MSG_CONTACTS		0x0013
> 
> #define STATUS_ONLINE		0x00000000
> #define STATUS_AWAY		0x00000001
> #define STATUS_DND		0x00000013
> #define STATUS_INVISIBLE	0x00000100
> #define STATUS_OCCUPIED		0x00000010
> #define STATUS_NA		0x00000004
> #define STATUS_CHAT		0x00000020
> 
> /* Offsets for all packets measured from the start of the payload; i.e.
>  * with the ICQ header removed
>  */
> #define CMD_ACK			0x000a
> #define CMD_ACK_RANDOM		0x0000
> 
> #define CMD_SEND_MSG		0x010E
> #define CMD_SEND_MSG_RECV_UIN	0x0000
> #define CMD_SEND_MSG_MSG_TYPE	0x0004
> #define CMD_SEND_MSG_MSG_LEN	0x0006
> #define CMD_SEND_MSG_MSG_TEXT	0x0008
> /* The rest of the packet should be a null-term string */
> 
> #define CMD_LOGIN		0x03E8
> #define CMD_LOGIN_TIME		0x0000
> #define CMD_LOGIN_PORT		0x0004
> #define CMD_LOGIN_PASSLEN	0x0008
> #define CMD_LOGIN_PASSWD	0x000A
> /* The password is variable length; so when we've decoded the passwd,
>  * the structure starts counting at 0 again.
>  */
> #define CMD_LOGIN_IP		0x0004
> #define CMD_LOGIN_STATUS	0x0009
> 
> 
> cmdcode msgTypeCode[] = {
>     { "MSG_TEXT", MSG_TEXT },
>     { "MSG_URL", MSG_URL },
>     { "MSG_AUTH_REQ", MSG_AUTH_REQ },
>     { "MSG_AUTH", MSG_AUTH },
>     { "MSG_USER_ADDED", MSG_USER_ADDED},
>     { "MSG_CONTACTS", MSG_CONTACTS},
>     { NULL, 0}
> };
> 
> cmdcode statusCode[] = {
>     { "ONLINE", STATUS_ONLINE },
>     { "AWAY", STATUS_AWAY },
>     { "DND", STATUS_DND },
>     { "INVISIBLE", STATUS_INVISIBLE },
>     { "OCCUPIED", STATUS_OCCUPIED },
>     { "NA", STATUS_NA },
>     { "Free for Chat", STATUS_CHAT },
>     { NULL, 0}
> };
> 
125,127c191,193
<     { "CMD_ACK", 10 },
<     { "CMD_SEND_MESSAGE", 270 },
<     { "CMD_LOGIN", 1000 },
---
>     { "CMD_ACK", CMD_ACK },
>     { "CMD_SEND_MESSAGE", CMD_SEND_MSG },
>     { "CMD_LOGIN", CMD_LOGIN },
160,178d225
< typedef struct {
<     u_int32_t random;
< } cl_cmd_ack;
< 
< typedef struct _cl_cmd_send_msg {
< #define MSG_TEXT	0x0100
< #define MSG_URL		0x0400
< #define MSG_AUTH_REQ	0x0600
< #define MSG_AUTH	0x0800
< #define MSG_USER_ADDED	0x0c00
< #define MSG_CONTACTS	0x1300
<     u_int32_t receiverUIN;
<     u_int16_t msgType;
<     u_int16_t msgLen;
<     /*
<      * Followed by char[msgLen]
<      */
< } cl_cmd_send_msg;
< 
206c253
<     while (p->code != 0) {
---
>     while (p->descr != NULL) {
216c263,287
< void
---
> static char*
> findMsgType(int num)
> {
>     return findcmd(msgTypeCode, num);
> }
> 
> static char*
> findClientCmd(int num)
> {
>     return findcmd(clientCmdCode, num);
> }
> 
> static char*
> findServerCmd(int num)
> {
>     return findcmd(serverCmdCode, num);
> }
> 
> static char*
> findStatus(int num)
> {
>     return findcmd(statusCode, num);
> }
> 
> static void
352a424,751
>  * Find first occurrence of ch in buf
>  * Buf is max size big.
>  */
> static char*
> strnchr(const u_char* buf, u_char ch, int size)
> {
>     int i;
>     u_char* p = (u_char*) buf;
>     for (i=0;(*p) && (*p!=ch) && (i<size); p++, i++)
> 	;
>     if ((*p == '\0') || (i>=size))
> 	return NULL;
>     return p;
> }
> 
> static void
> icqv5_cmd_ack(proto_tree* tree,/* Tree to put the data in */
> 		     const u_char* pd, /* Packet content */
> 		     int offset, /* Offset from the start of the packet to the content */
> 		     int size)	/* Number of chars left to do */
> {
>     u_int32_t random = pletohl(pd + CMD_ACK_RANDOM);
>     proto_tree* subtree;
>     proto_item* ti;
> 
>     if (tree){
> 	ti = proto_tree_add_item_format(tree,
> 					hf_icq_cmd,
> 					offset,
> 					4,
> 					CMD_ACK,
> 					"%s : %d",
> 					findClientCmd(CMD_ACK),
> 					CMD_ACK);
> 	subtree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
> 	proto_tree_add_text(subtree,
> 			    offset + CMD_ACK_RANDOM,
> 			    4,
> 			    "Random: 0x%08lx", random);
>     }
> }
> 
> static void
> icqv5_cmd_send_msg(proto_tree* tree,
> 		   const u_char* pd,
> 		   int offset,
> 		   int size)
> {
>     proto_tree* subtree;
>     proto_item* ti;
>     u_int32_t receiverUIN = 0xffffffff;
>     u_int16_t msgType = 0xffff;
>     u_int16_t msgLen = 0xffff;
>     u_char* msgText = NULL;
>     int left = size;		/* left chars to do */
>     int i,n,j;
>     static char* auth_req_field_descr[] = {
> 	"Nickname",
> 	"First name",
> 	"Last name",
> 	"Email address",
> 	"Reason"};
>     
>     if (left >= 4) {
> 	receiverUIN = pletohl(pd + CMD_SEND_MSG_RECV_UIN);
> 	left -= 4;
>     }
>     if (left >= 2) {
> 	msgType = pletohs(pd + CMD_SEND_MSG_MSG_TYPE);
> 	left -= 2;
>     }
>     if (left >= 2) {
> 	msgLen = pletohs(pd + CMD_SEND_MSG_MSG_LEN);
> 	left -= 2;
>     }
>     if (tree) {
> 	ti = proto_tree_add_item_format(tree,
> 					hf_icq_cmd,
> 					offset,
> 					size,
> 					CMD_SEND_MSG,
> 					"Body");
> 	subtree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
> 	proto_tree_add_text(subtree,
> 			    offset + CMD_SEND_MSG_RECV_UIN,
> 			    4,
> 			    "Receiver UIN: %ld", receiverUIN);
> 	ti = proto_tree_add_text(subtree,
> 				 offset + CMD_SEND_MSG_MSG_TYPE,
> 				 2,
> 				 "Type: %d (%s)", msgType, findMsgType(msgType));
> 	proto_tree_add_text(subtree,
> 			    offset + CMD_SEND_MSG_MSG_LEN,
> 			    2,
> 			    "Length: %d", msgLen);
> 
> 	/* It's silly to do anything if there's nothing left */
> 	if (left==0)
> 	    return;
> 	if (msgLen == 0)
> 	    return;
> 	/* Create a subtree for every message type */
> 	switch(msgType) {
> 	case 0xffff:		/* Field unknown */
> 	    break;
> 	case MSG_TEXT:
> 	    msgText = g_malloc(left + 1);
> 	    strncpy(msgText, pd + CMD_SEND_MSG_MSG_TEXT, left);
> 	    msgText[left] = '\0';
> 	    proto_tree_add_text(subtree,
> 				offset + CMD_SEND_MSG_MSG_TEXT,
> 				left,
> 				"Msg: %s", msgText);
> 	    g_free(msgText);
> 	    break;
> 	case MSG_URL:
> 	    /* Two parts, a description and the URL. Separeted by FE */
> 	    for (i=0;i<left;i++) {
> 		if (pd[CMD_SEND_MSG_MSG_TEXT + i] == 0xfe)
> 		    break;
> 	    }
> 	    msgText = g_malloc(i + 1);
> 	    strncpy(msgText, pd + CMD_SEND_MSG_MSG_TEXT, i);
> 	    if (i==left)
> 		msgText[i] = '\0';
> 	    else
> 		msgText[i-1] = '\0';
> 	    proto_tree_add_text(subtree,
> 				offset + CMD_SEND_MSG_MSG_TEXT,
> 				i,
> 				"Description: %s", msgText);
> 	    if (i==left)
> 		break;
> 	    msgText = g_realloc(msgText, left - i);
> 	    strncpy(msgText, pd + CMD_SEND_MSG_MSG_TEXT + i + 1, left - i - 1);
> 	    msgText[left - i] = '\0';
> 	    proto_tree_add_text(subtree,
> 				offset + CMD_SEND_MSG_MSG_TEXT,
> 				i,
> 				"URL: %s", msgText);
> 	    g_free(msgText);
> 	    break;
> 	case MSG_AUTH_REQ:
> 	    /* Five parts, separated by FE */
> 	    i = 0;
> 	    j = 0;
> 	    msgText = NULL;
> 	    for (n = 0; n < 5; n++) {
> 		for (;
> 		     (i<left) && (pd[CMD_SEND_MSG_MSG_TEXT+i]!=0xfe);
> 		     i++)
> 		    ;
> 		msgText = g_realloc(msgText, i-j);
> 		strncpy(msgText, pd + CMD_SEND_MSG_MSG_TEXT + j, i - j - 1);
> 		msgText[i-j-1] = '\0';
> 		proto_tree_add_text(subtree,
> 				    offset + CMD_SEND_MSG_MSG_TEXT + j,
> 				    i - j - 1,
> 				    "%s: %s", auth_req_field_descr[n], msgText);
> 		j = ++i;
> 	    }
> 	    if (msgText != NULL)
> 		g_free(msgText);
> 	    break;
> 	case MSG_USER_ADDED:
> 	    /* Create a new subtree */
> 	    subtree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
> 	    /* Four parts, separated by FE */
> 	    i = 0;
> 	    j = 0;
>             /* This is necessary, because g_realloc does not behave like
> 	     * g_malloc if the first parameter == NULL */
> 	    msgText = g_malloc(64);
> 	    for (n = 0; n < 4; n++) {
> 		for (;
> 		     (i<left) && (pd[CMD_SEND_MSG_MSG_TEXT+i]!=0xfe);
> 		     i++)
> 		    ;
> 		msgText = g_realloc(msgText, i-j+1);
> 		strncpy(msgText, pd + CMD_SEND_MSG_MSG_TEXT + j, i - j);
> 		msgText[i-j] = '\0';
> 		proto_tree_add_text(subtree,
> 				    offset + CMD_SEND_MSG_MSG_TEXT + j,
> 				    i - j,
> 				    "%s: %s", auth_req_field_descr[n], msgText);
> 		j = ++i;
> 	    }
> 	    if (msgText != NULL)
> 		g_free(msgText);
> 	    break;
> 	case MSG_CONTACTS:
> 	{
> 	    u_char* p = (u_char*) &pd[CMD_SEND_MSG_MSG_TEXT];
> 	    u_char* pprev = p;
> 	    int sz = 0;		/* Size of the current element */
> 	    int n = 0;		/* The nth element */
> 	    int done = 0;	/* Number of chars processed */
> 	    u_char* msgText2 = NULL;
> 	    msgText = NULL;
> 	    /* Create a new subtree */
> 	    subtree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
> 	    while (p!=NULL) {
> 		p = strnchr(pprev, 0xfe, left);
> 		
> 		if (p!=NULL)
> 		    sz = (int)(p - pprev);
> 		else
> 		    sz = left;
> 		msgText = g_realloc(msgText, sz+1);
> 		strncpy(msgText, pprev, sz);
> 		msgText[sz] = '\0';
> 
> 		if (n == 0) {
> 		    /* The first element is the number of Nick/UIN pairs follow */
> 		    proto_tree_add_text(subtree,
> 					offset + CMD_SEND_MSG_MSG_TEXT + done,
> 					sz,
> 					"Number of pairs: %s", msgText);
> 		    n++;
> 		} else if (p!=NULL) {
> 		    int svsz = sz;
> 		    left -= (sz+1);
> 		    pprev = p + 1;
> 		    p = strnchr(pprev, 0xfe, left);
> 		    if (p!=NULL)
> 			sz = (int)(p - pprev);
> 		    else
> 			sz = left;
> 		    msgText2 = g_malloc(sz+1);
> 		    strncpy(msgText2, pprev, sz);
> 		    msgText2[sz] = '\0';
> 
> 		    proto_tree_add_text(subtree,
> 					offset + CMD_SEND_MSG_MSG_TEXT + done,
> 					sz + svsz + 2,
> 					"%s:%s", msgText, msgText2);
> 		    n+=2;
> 		    g_free(msgText2);
> 		}
> 		
> 		left -= (sz+1);
> 		pprev = p+1;
> 	    }
> 	    if (msgText != NULL)
> 		g_free(msgText);
> 	    break;
> 	}}
>     }
> }
> 
> static void
> icqv5_cmd_login(proto_tree* tree,
> 		const u_char* pd,
> 		int offset,
> 		int size)
> {
>     proto_item* ti;
>     proto_tree* subtree;
>     u_int32_t theTime = -1;
>     u_int32_t port = -1;
>     u_int32_t passwdLen = -1;
>     char* password = NULL;
>     u_int32_t ipAddr = INADDR_ANY;
>     u_int32_t status = -1;
>     u_int32_t left = size;
> 
>     if (left>=4) {
> 	theTime = pletohl(pd + CMD_LOGIN_TIME);
>     }
>     if (left>=8) {
> 	port = pletohl(pd + CMD_LOGIN_PORT);
>     }
>     if (left>=10) {
> 	passwdLen = pletohs(pd + CMD_LOGIN_PASSLEN);
>     }
>     if (left>=10+passwdLen) {
> 	password = g_malloc(passwdLen);
> 	strncpy(password, pd + CMD_LOGIN_PASSWD, passwdLen);
>     }
> 
>     if (left>=10+passwdLen+CMD_LOGIN_IP+4) {
> 	ipAddr = pletohs(pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP);
>     }
>     if (left>=10+passwdLen+CMD_LOGIN_STATUS+4) {
> 	status = pletohs(pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS);
>     }
>     if (tree) {
> 	ti = proto_tree_add_item_format(tree,
> 					hf_icq_cmd,
> 					offset,
> 					size,
> 					CMD_SEND_MSG,
> 					"Body");
> 	subtree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
> 	if (theTime!=-1)
> 	    proto_tree_add_text(subtree,
> 				offset + CMD_LOGIN_TIME,
> 				4,
> 				"Time: %d = %s", theTime, ctime(&theTime));
> 	if (port!=-1)
> 	    proto_tree_add_text(subtree,
> 				offset + CMD_LOGIN_PORT,
> 				4,
> 				"Port: %d", port);
> 	if ((passwdLen!=-1) && (password!=NULL))
> 	    proto_tree_add_text(subtree,
> 				offset + CMD_LOGIN_PASSLEN,
> 				2 + passwdLen,
> 				"Passwd: %s", password);
> 	/*
> 	 * The following is quick and dirty. Should use inet_ntop
> 	 */
> 	if (ipAddr!=INADDR_ANY)
> 	    proto_tree_add_text(subtree,
> 				offset + CMD_LOGIN_PASSWD + CMD_LOGIN_IP,
> 				4,
> 				"IP: %s", inet_ntoa(ipAddr));
> 	if (status!=-1)
> 	    proto_tree_add_text(subtree,
> 				offset + CMD_LOGIN_PASSWD + CMD_LOGIN_IP,
> 				4,
> 				"Status: %s", findStatus(status));
>     }
>     if (password!=NULL)
> 	g_free(password);
> }
> 
> /*
361a761
>     proto_tree *icq_header_tree = NULL;
388a789,791
> 
> 	if (check_col(fd, COL_INFO))
> 	    col_add_fstr(fd, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
396c799,801
< 				 "ICQv5 Client: len %d", pktsize);
---
> 				 "ICQv5 %s (len %d)",
> 				 findClientCmd(cmd),
> 				 pktsize);
398,404c803,809
< 	proto_tree_add_item_format(icq_tree,
< 				   hf_icq_cmd,
< 				   offset+ICQ5_CL_CMD,
< 				   2,
< 				   cmd,
< 				   "Command: %d (%s)", cmd, findcmd(clientCmdCode, cmd));
< 	proto_tree_add_item_format(icq_tree,
---
> 	ti = proto_tree_add_text(icq_tree,
> 				 offset,
> 				 ICQ5_CL_HDRSIZE,
> 				 "Header");
> 	icq_header_tree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
> 					
> 	proto_tree_add_item_format(icq_header_tree,
411c816
< 	proto_tree_add_item_format(icq_tree,
---
> 	proto_tree_add_item_format(icq_header_tree,
418c823
< 	proto_tree_add_item_format(icq_tree,
---
> 	proto_tree_add_item_format(icq_header_tree,
425c830
< 	proto_tree_add_text(icq_tree,
---
> 	proto_tree_add_text(icq_header_tree,
429c834
< 	proto_tree_add_text(icq_tree,
---
> 	proto_tree_add_text(icq_header_tree,
432a838,865
> 	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:
> 	    icqv5_cmd_send_msg(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;
> 	default:
> 	    proto_tree_add_item_format(icq_tree,
> 				       hf_icq_cmd,
> 				       offset+ICQ5_CL_CMD,
> 				       2,
> 				       cmd,
> 				       "Command: %d (%s)", cmd, findcmd(clientCmdCode, cmd));
> 	    break;
> 	}
439a873
> 
463a898,900
>     if (check_col(fd, COL_INFO))
> 	col_add_fstr(fd, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
> 
479c916
< 				   cmd, findcmd(serverCmdCode, cmd));
---
> 				   cmd, findServerCmd(cmd));
538c975
<       fprintf(stderr, "ICQ: Unknown version\n");
---
>       fprintf(stderr, "ICQ: Unknown version (%d)\n", version);
Index: packet.h
===================================================================
RCS file: /cvsroot/ethereal/packet.h,v
retrieving revision 1.120
diff -r1.120 packet.h
254a255
> 	ETT_ICQ_SUBTREE,
--
Kojak