From bba1ad82d1179e0fe43d2aab42f418613d8a3062 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Sat, 6 Nov 1999 03:08:34 +0000 Subject: [PATCH] Updates to the ICQ decoder, from Kojak. svn path=/trunk/; revision=981 --- packet-icq.c | 1664 +++++++++++++++++++++++++++++++++++++++++++------- packet.h | 11 +- 2 files changed, 1440 insertions(+), 235 deletions(-) diff --git a/packet-icq.c b/packet-icq.c index 13f69e9a38..ea9aea34a6 100644 --- a/packet-icq.c +++ b/packet-icq.c @@ -1,7 +1,7 @@ /* packet-icq.c * Routines for ICQ packet disassembly * - * $Id: packet-icq.c,v 1.4 1999/11/03 06:21:35 guy Exp $ + * $Id: packet-icq.c,v 1.5 1999/11/06 03:08:33 guy Exp $ * * Ethereal - Network traffic analyzer * By Johan Feyaerts @@ -74,6 +74,21 @@ int hf_icq_cmd =-1; int hf_icq_sessionid =-1; int hf_icq_checkcode =-1; int hf_icq_decode = -1; +int hf_icq_type = -1; + +enum { ICQ5_client, ICQ5_server}; + +void dissect_icqv5(const u_char *pd, + int offset, + frame_data *fd, + proto_tree *tree); + +static void +dissect_icqv5Server(const u_char *pd, + int offset, + frame_data *fd, + proto_tree *tree, + guint32 pktsize); /* Offsets of fields in the ICQ headers */ /* Can be 0x0002 or 0x0005 */ @@ -105,20 +120,80 @@ typedef struct _cmdcode { int code; } cmdcode; +#define SRV_ACK 0x000a + +#define SRV_GO_AWAY 0x0028 + +#define SRV_NEW_UIN 0x0046 + +/* LOGIN_REPLY is very scary. It has a lot of fields that are undocumented + * Only the IP field makes sense */ +#define SRV_LOGIN_REPLY 0x005a +#define SRV_LOGIN_REPLY_IP 0x000c + +#define SRV_BAD_PASS 0x0064 + +#define SRV_USER_ONLINE 0x006e +#define SRV_USER_ONL_UIN 0x0000 +#define SRV_USER_ONL_IP 0x0004 +#define SRV_USER_ONL_PORT 0x0008 +#define SRV_USER_ONL_REALIP 0x000c +#define SRV_USER_ONL_X1 0x0010 +#define SRV_USER_ONL_STATUS 0x0011 +#define SRV_USER_ONL_X2 0x0015 + +#define SRV_USER_OFFLINE 0x0078 +#define SRV_USER_OFFLINE_UIN 0x0000 + +#define SRV_MULTI 0x0212 +#define SRV_MULTI_NUM 0x0000 + +#define SRV_META_USER 0x03de +#define SRV_META_USER_SUBCMD 0x0000 +#define SRV_META_USER_RESULT 0x0002 +#define SRV_META_USER_DATA 0x0003 + +#define SRV_UPDATE_SUCCESS 0x01e0 + +#define SRV_UPDATE_FAIL 0x01ea + +/* + * ICQv5 SRV_META_USER subcommands + */ +#define META_USER_FOUND 0x019a +#define META_ABOUT 0x00e6 +#define META_USER_INFO 0x00c8 + +#define SRV_RECV_MESSAGE 0x00dc +#define SRV_RECV_MSG_UIN 0x0000 +#define SRV_RECV_MSG_YEAR 0x0004 +#define SRV_RECV_MSG_MONTH 0x0006 +#define SRV_RECV_MSG_DAY 0x0007 +#define SRV_RECV_MSG_HOUR 0x0008 +#define SRV_RECV_MSG_MINUTE 0x0009 +#define SRV_RECV_MSG_MSG_TYPE 0x000a + +cmdcode serverMetaSubCmdCode[] = { + { "META_USER_FOUND", META_USER_FOUND }, + { "META_ABOUT", META_ABOUT }, + { "META_USER_INFO", META_USER_INFO }, + { NULL, -1 } +}; + cmdcode serverCmdCode[] = { - { "SRV_ACK", 10 }, - { "SRV_GO_AWAY", 40 }, - { "SRV_NEW_UIN", 70 }, - { "SRV_LOGIN_REPLY", 90 }, - { "SRV_BAD_PASS", 100 }, - { "SRV_USER_ONLINE", 110 }, - { "SRV_USER_OFFLINE", 120 }, + { "SRV_ACK", SRV_ACK }, + { "SRV_GO_AWAY", SRV_GO_AWAY }, + { "SRV_NEW_UIN", SRV_NEW_UIN }, + { "SRV_LOGIN_REPLY", SRV_LOGIN_REPLY }, + { "SRV_BAD_PASS", SRV_BAD_PASS }, + { "SRV_USER_ONLINE", SRV_USER_ONLINE }, + { "SRV_USER_OFFLINE", SRV_USER_OFFLINE }, { "SRV_QUERY", 130 }, { "SRV_USER_FOUND", 140 }, { "SRV_END_OF_SEARCH", 160 }, { "SRV_NEW_USER", 180 }, { "SRV_UPDATE_EXT", 200 }, - { "SRV_RECV_MESSAGE", 220 }, + { "SRV_RECV_MESSAGE", SRV_RECV_MESSAGE }, { "SRV_X2", 230 }, { "SRV_NOT_CONNECTED", 240 }, { "SRV_TRY_AGAIN", 250 }, @@ -127,14 +202,14 @@ cmdcode serverCmdCode[] = { { "SRV_EXT_INFO_REPLY", 290 }, { "SRV_STATUS_UPDATE", 420 }, { "SRV_SYSTEM_MESSAGE", 450 }, - { "SRV_UPDATE_SUCCESS", 480 }, - { "SRV_UPDATE_FAIL", 490 }, + { "SRV_UPDATE_SUCCESS", SRV_UPDATE_SUCCESS }, + { "SRV_UPDATE_FAIL", SRV_UPDATE_FAIL }, { "SRV_AUTH_UPDATE", 500 }, - { "SRV_MULTI_PACKET", 530 }, + { "SRV_MULTI_PACKET", SRV_MULTI }, { "SRV_X1", 540 }, { "SRV_RAND_USER", 590 }, - { "SRV_META_USER", 990 }, - { NULL, 0 } + { "SRV_META_USER", SRV_META_USER }, + { NULL, -1 } }; #define MSG_TEXT 0x0001 @@ -142,6 +217,7 @@ cmdcode serverCmdCode[] = { #define MSG_AUTH_REQ 0x0006 #define MSG_AUTH 0x0008 #define MSG_USER_ADDED 0x000c +#define MSG_EMAIL 0x000e #define MSG_CONTACTS 0x0013 #define STATUS_ONLINE 0x00000000 @@ -176,6 +252,37 @@ cmdcode serverCmdCode[] = { #define CMD_LOGIN_IP 0x0004 #define CMD_LOGIN_STATUS 0x0009 +#define CMD_CONTACT_LIST 0x0406 +#define CMD_CONTACT_LIST_NUM 0x0000 + +#define CMD_USER_META 0x064a + +#define CMD_REG_NEW_USER 0x03fc + +#define CMD_ACK_MESSAGES 0x0442 +#define CMD_ACK_MESSAGES_RANDOM 0x0000 + +#define CMD_KEEP_ALIVE 0x042e +#define CMD_KEEP_ALIVE_RANDOM 0x0000 + +#define CMD_SEND_TEXT_CODE 0x0438 +#define CMD_SEND_TEXT_CODE_LEN 0x0000 +#define CMD_SEND_TEXT_CODE_TEXT 0x0002 + +#define CMD_QUERY_SERVERS 0x04ba + +#define CMD_QUERY_ADDONS 0x04c4 + +#define CMD_STATUS_CHANGE 0x04d8 +#define CMD_STATUS_CHANGE_STATUS 0x0000 + +#define CMD_ADD_TO_LIST 0x053c +#define CMD_ADD_TO_LIST_UIN 0x0000 + +#define CMD_RAND_SEARCH 0x056e +#define CMD_RAND_SEARCH_GROUP 0x0000 + +#define CMD_META_USER 0x064a cmdcode msgTypeCode[] = { { "MSG_TEXT", MSG_TEXT }, @@ -183,6 +290,7 @@ cmdcode msgTypeCode[] = { { "MSG_AUTH_REQ", MSG_AUTH_REQ }, { "MSG_AUTH", MSG_AUTH }, { "MSG_USER_ADDED", MSG_USER_ADDED}, + { "MSG_EMAIL", MSG_EMAIL}, { "MSG_CONTACTS", MSG_CONTACTS}, { NULL, 0} }; @@ -202,13 +310,13 @@ cmdcode clientCmdCode[] = { { "CMD_ACK", CMD_ACK }, { "CMD_SEND_MESSAGE", CMD_SEND_MSG }, { "CMD_LOGIN", CMD_LOGIN }, - { "CMD_REG_NEW_USER", 1020 }, + { "CMD_REG_NEW_USER", CMD_REG_NEW_USER }, { "CMD_CONTACT_LIST", 1030 }, { "CMD_SEARCH_UIN", 1050 }, { "CMD_SEARCH_USER", 1060 }, { "CMD_KEEP_ALIVE", 1070 }, - { "CMD_SEND_TEXT_CODE", 1080 }, - { "CMD_ACK_MESSAGES", 1090 }, + { "CMD_SEND_TEXT_CODE", CMD_SEND_TEXT_CODE }, + { "CMD_ACK_MESSAGES", CMD_ACK_MESSAGES }, { "CMD_LOGIN_1", 1100 }, { "CMD_MSG_TO_NEW_USER", 1110 }, { "CMD_INFO_REQ", 1120 }, @@ -216,18 +324,18 @@ cmdcode clientCmdCode[] = { { "CMD_CHANGE_PW", 1180 }, { "CMD_NEW_USER_INFO", 1190 }, { "CMD_UPDATE_EXT_INFO", 1200 }, - { "CMD_QUERY_SERVERS", 1210 }, - { "CMD_QUERY_ADDONS", 1220 }, - { "CMD_STATUS_CHANGE", 1240 }, + { "CMD_QUERY_SERVERS", CMD_QUERY_SERVERS }, + { "CMD_QUERY_ADDONS", CMD_QUERY_ADDONS }, + { "CMD_STATUS_CHANGE", CMD_STATUS_CHANGE }, { "CMD_NEW_USER_1", 1260 }, { "CMD_UPDATE_INFO", 1290 }, { "CMD_AUTH_UPDATE", 1300 }, { "CMD_KEEP_ALIVE2", 1310 }, { "CMD_LOGIN_2", 1320 }, - { "CMD_ADD_TO_LIST", 1340 }, + { "CMD_ADD_TO_LIST", CMD_ADD_TO_LIST }, { "CMD_RAND_SET", 1380 }, - { "CMD_RAND_SEARCH", 1390 }, - { "CMD_META_USER", 1610 }, + { "CMD_RAND_SEARCH", CMD_RAND_SEARCH }, + { "CMD_META_USER", CMD_META_USER }, { "CMD_INVIS_LIST", 1700 }, { "CMD_VIS_LIST", 1710 }, { "CMD_UPDATE_LIST", 1720 }, @@ -277,6 +385,12 @@ findMsgType(int num) return findcmd(msgTypeCode, num); } +static char* +findSubCmd(int num) +{ + return findcmd(serverMetaSubCmdCode, num); +}; + static char* findClientCmd(int num) { @@ -447,6 +561,254 @@ strnchr(const u_char* buf, u_char ch, int size) return p; } + +static void +icqv5_decode_msgType(proto_tree* tree, + const unsigned char* pd, /* From start of messageType */ + int offset, + int size) +{ + proto_item* ti = NULL; + proto_tree* subtree = NULL; + int left = size; + char *msgText = NULL; + guint16 msgType = -1; + guint16 msgLen = -1; + int i,j,n; + static char* auth_req_field_descr[] = { + "Nickname", + "First name", + "Last name", + "Email address", + "Reason"}; + static char* emain_field_descr[] = { + "Nickname", + "First name", + "Last name", + "Email address", + "Unknown", + "Text\n" + }; + + enum {OFF_MSG_TYPE=0, + OFF_MSG_LEN=2, + OFF_MSG_TEXT=4}; + + + if (left >= sizeof(guint16)) { + msgType = pletohs(pd + OFF_MSG_TYPE); + left -= sizeof(guint16); + } + if (left >= sizeof(guint16)) { + msgLen = pletohs(pd + OFF_MSG_LEN); + left -= sizeof(guint16); + } + + ti = proto_tree_add_text(tree, + offset , + 2, + "Type: %d (%s)", msgType, findMsgType(msgType)); + /* Create a new subtree */ + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY_PARTS); + + switch(msgType) { + case 0xffff: /* Field unknown */ + break; + default: + fprintf(stderr, "Unknown msgType: %d (%04x)\n", msgType, msgType); + break; + case MSG_TEXT: + msgText = g_malloc(left + 1); + strncpy(msgText, pd + OFF_MSG_TEXT, left); + msgText[left] = '\0'; + proto_tree_add_text(subtree, + offset + OFF_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;ij) { + msgText = g_realloc(msgText, i-j); + strncpy(msgText, pd + OFF_MSG_TEXT + j, i - j - 1); + msgText[i-j-1] = '\0'; + proto_tree_add_text(subtree, + offset + OFF_MSG_TEXT + j, + i - j - 1, + "%s: %s", emain_field_descr[n], msgText); + } else { + proto_tree_add_text(subtree, + offset + OFF_MSG_TEXT + j, + 0, + "%s: %s", emain_field_descr[n], "(empty)"); + } + j = ++i; + } + if (msgText != NULL) + g_free(msgText); + break; + + case MSG_AUTH: + { + /* Three bytes, first is a char signifying success */ + unsigned char auth_suc = pd[OFF_MSG_LEN]; + guint16 x1 = pd[OFF_MSG_LEN+1]; + proto_tree_add_text(subtree, + offset + OFF_MSG_LEN, + 1, + "Authorization: (%d) %s",auth_suc, + (auth_suc==0)?"Denied":"Allowed"); + proto_tree_add_text(subtree, + offset + OFF_MSG_LEN + 1, + sizeof(guint16), + "x1: 0x%04x",x1); + break; + } + case MSG_AUTH_REQ: + /* Five parts, separated by FE */ + i = 0; + j = 0; + msgText = NULL; + for (n = 0; n < 5; n++) { + for (; + (i0 && (group<=sizeof(groups)/sizeof(const char*))) + proto_tree_add_text(subtree, + offset + CMD_RAND_SEARCH_GROUP, + 4, + "Group: (%d) %s", group, groups[group-1]); + else + proto_tree_add_text(subtree, + offset + CMD_RAND_SEARCH_GROUP, + 4, + "Group: (%d)", group); + } +} + +static void +icqv5_cmd_ack_messages(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 */ +{ + guint32 random = pletohl(pd + CMD_ACK_MESSAGES_RANDOM); + proto_tree* subtree; + proto_item* ti; + + if (tree){ + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + 4, + CMD_ACK_MESSAGES, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + proto_tree_add_text(subtree, + offset + CMD_ACK_MESSAGES_RANDOM, + 4, + "Random: 0x%08lx", random); + } +} + +static void +icqv5_cmd_keep_alive(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 */ +{ + guint32 random = pletohl(pd + CMD_KEEP_ALIVE_RANDOM); + proto_tree* subtree; + proto_item* ti; + + if (tree){ + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + 4, + CMD_KEEP_ALIVE, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + proto_tree_add_text(subtree, + offset + CMD_KEEP_ALIVE_RANDOM, + 4, + "Random: 0x%08lx", random); + } +} + +static void +icqv5_cmd_send_text_code(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 */ +{ + proto_tree* subtree; + proto_item* ti; + gint16 len = -1; + guint16 x1 = -1; + char* text = NULL; + int left = size; /* The amount of data left to analyse */ + + if (left>=sizeof(gint16)) { + len = pletohs(pd+CMD_SEND_TEXT_CODE_LEN); + left -= sizeof(gint16); + } + if (len>=0) { + len = MIN(len, left); + text = g_malloc(len+1); + memcpy(text, pd + CMD_SEND_TEXT_CODE_TEXT, len); + text[len] = '\0'; + left -= len; + } + if (left>=sizeof(gint16)) { + x1 = pletohs(pd + size - left); + left -= sizeof(gint16); + } + if (tree){ + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + left, + CMD_KEEP_ALIVE, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + proto_tree_add_text(subtree, + offset + CMD_SEND_TEXT_CODE_LEN, + 2, + "Length: %d", len); + proto_tree_add_text(subtree, + offset + CMD_SEND_TEXT_CODE_TEXT, + len, + "Text: %s",text); + proto_tree_add_text(subtree, + offset + CMD_SEND_TEXT_CODE_TEXT + len, + 2, + "X1: 0x%04x", x1); + } + if (text!=NULL) + g_free(text); +} + +static void +icqv5_cmd_add_to_list(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 */ +{ + guint32 uin = -1; + proto_tree* subtree; + proto_item* ti; + if (size>=4) + uin = pletohl(pd + CMD_ADD_TO_LIST); + if (tree){ + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + 4, + CMD_ADD_TO_LIST, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + proto_tree_add_text(subtree, + offset + CMD_ADD_TO_LIST_UIN, + 4, + "UIN: %ld", uin); + } +} + +static void +icqv5_cmd_status_change(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 */ +{ + guint32 status = -1; + proto_tree* subtree; + proto_item* ti; + + if (size >= CMD_STATUS_CHANGE_STATUS + 4) + status = pletohl(pd + CMD_STATUS_CHANGE_STATUS); + if (tree){ + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + 4, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + if (status!=-1) + proto_tree_add_text(subtree, + offset + CMD_STATUS_CHANGE_STATUS, + 4, + "Status: %08x (%s)", status, findStatus(status)); + } +} + static void icqv5_cmd_send_msg(proto_tree* tree, const u_char* pd, @@ -485,15 +1046,7 @@ icqv5_cmd_send_msg(proto_tree* tree, guint32 receiverUIN = 0xffffffff; guint16 msgType = 0xffff; guint16 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); @@ -514,171 +1067,20 @@ icqv5_cmd_send_msg(proto_tree* tree, size, CMD_SEND_MSG, "Body"); - subtree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); 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= CMD_CONTACT_LIST_NUM + 1) + num = pd[CMD_CONTACT_LIST_NUM]; + + if (tree) { + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + size, + CMD_CONTACT_LIST, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + proto_tree_add_text(subtree, + offset + CMD_CONTACT_LIST, + 1, + "Number of uins: %d", num); + /* + * A sequence of num times UIN follows + */ + offset += (CMD_CONTACT_LIST_NUM + 1); + left = size; + p = &pd[CMD_CONTACT_LIST_NUM + 1]; + for (i = 0; (i0);i++) { + if (left>=4) { + uin = pletohl(p); + proto_tree_add_text(subtree, + offset, + 4, + "UIN[%d]: %ld",i,uin); + p += 4; + offset += 4; + left -= 4; + } + } + } +} + +static void +icqv5_cmd_no_params(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 */ + int cmd) +{ + proto_tree* subtree; + proto_item* ti; + + if (tree){ + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + 0, + cmd, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + proto_tree_add_text(subtree, + offset, + 0, + "No parameters"); + } +} + +/********************** + * + * Server commands + * + ********************** + */ +static void +icqv5_srv_no_params(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 */ + int cmd) +{ + proto_tree* subtree; + proto_item* ti; + + if (tree){ + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + 0, + cmd, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + proto_tree_add_text(subtree, + offset, + 0, + "No Parameters"); + } +} + +static void +icqv5_srv_login_reply(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 */ +{ + proto_tree* subtree; + proto_item* ti; + const u_char *ipAddrp = NULL; + + if (size >= SRV_LOGIN_REPLY_IP + 4) + ipAddrp = &pd[SRV_LOGIN_REPLY_IP]; + + if (tree) { + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + SRV_LOGIN_REPLY_IP + 8, + SRV_LOGIN_REPLY, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + proto_tree_add_text(subtree, + offset + SRV_LOGIN_REPLY_IP, + 4, + "IP: %s", ip_to_str(ipAddrp)); + } +} + +static void +icqv5_srv_user_online(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 */ +{ + proto_tree* subtree; + proto_item* ti; + guint32 uin = -1; + const u_char *ipAddrp = NULL; + guint32 port = -1; + const u_char *realipAddrp = NULL; + guint32 status = -1; + guint32 version = -1; + + if (size >= SRV_USER_ONL_UIN + 4) + uin = pletohl(pd + SRV_USER_ONL_UIN); + + if (size >= SRV_USER_ONL_IP + 4) + ipAddrp = &pd[SRV_USER_ONL_IP]; + + if (size >= SRV_USER_ONL_PORT + 4) + port = pletohl(pd + SRV_USER_ONL_PORT); + + if (size >= SRV_USER_ONL_REALIP + 4) + realipAddrp = &pd[SRV_USER_ONL_REALIP]; + + if (size >= SRV_USER_ONL_STATUS + 4) + status = pletohl(pd + SRV_USER_ONL_STATUS); + + /* + * Kojak: Hypothesis is that this field might be an encoding for the + * version used by the UIN that changed. To test this, I included + * this line to the code. + */ + if (size >= SRV_USER_ONL_X2 + 4) + version = pletohl(pd + SRV_USER_ONL_X2); + + if (tree) { + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + SRV_LOGIN_REPLY_IP + 8, + SRV_LOGIN_REPLY, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + proto_tree_add_text(subtree, + offset + SRV_USER_ONL_UIN, + 4, + "UIN: %d", uin); + proto_tree_add_text(subtree, + offset + SRV_USER_ONL_IP, + 4, + "IP: %s", ip_to_str(ipAddrp)); + proto_tree_add_text(subtree, + offset + SRV_USER_ONL_PORT, + 4, + "Port: %d", port); + proto_tree_add_text(subtree, + offset + SRV_USER_ONL_REALIP, + 4, + "RealIP: %s", ip_to_str(realipAddrp)); + proto_tree_add_text(subtree, + offset + SRV_USER_ONL_STATUS, + 4, + "Status: %s", findStatus(status)); + proto_tree_add_text(subtree, + offset + SRV_USER_ONL_X2, + 4, + "Version: %08x", version); + } +} + +static void +icqv5_srv_user_offline(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 */ +{ + proto_tree* subtree; + proto_item* ti; + guint32 uin = -1; + + if (size >= SRV_USER_OFFLINE + 4) + uin = pletohl(&pd[SRV_USER_OFFLINE]); + + if (tree) { + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + SRV_USER_OFFLINE_UIN + 4, + SRV_USER_OFFLINE, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + proto_tree_add_text(subtree, + offset + SRV_USER_OFFLINE_UIN, + 4, + "UIN: %d", uin); + } +} + +static void +icqv5_srv_multi(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 */ + frame_data* fd) +{ + proto_tree* subtree; + proto_item* ti; + unsigned char num = -1; + guint16 pktSz; + int i, left; + const u_char* p = NULL; + + if (size >= SRV_MULTI_NUM + 1) + num = pd[SRV_MULTI_NUM]; + + if (tree) { + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + size, + SRV_MULTI, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + proto_tree_add_text(subtree, + offset + SRV_MULTI_NUM, + 1, + "Number of pkts: %d", num); + /* + * A sequence of num times ( pktsize, packetData) follows + */ + offset += (SRV_MULTI_NUM + 1); + left = size; + p = &pd[SRV_MULTI_NUM + 1]; + for (i = 0; (i0);i++) { + if (left>=2) { + pktSz = pletohs(p); + p += 2; + offset += 2; + left -= 2; + if (left>=pktSz) { + dissect_icqv5Server(p, offset, fd, subtree, pktSz); + p += pktSz; + offset += pktSz; + left -= pktSz; + } + } + } + } +} + +static void +icqv5_srv_meta_user(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 */ +{ + proto_tree* subtree = NULL; + proto_item* ti = NULL; + int left = size; + const char* p = pd; + + guint16 subcmd = -1; + unsigned char result = -1; + + if (size>=SRV_META_USER_SUBCMD + 2) + subcmd = pletohs(pd+SRV_META_USER_SUBCMD); + if (size>=SRV_META_USER_RESULT + 1) + result = pd[SRV_META_USER_RESULT]; + + if (tree) { + ti = proto_tree_add_item_format(tree, + hf_icq_cmd, + offset, + size, + SRV_META_USER, + "Body"); + subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY); + ti = proto_tree_add_text(subtree, + offset + SRV_META_USER_SUBCMD, + 2, + "%s", findSubCmd(subcmd)); + proto_tree_add_text(subtree, + offset + SRV_META_USER_RESULT, + 1, + "%s", (result==0x0a)?"Success":"Failure"); + switch(subcmd) { + case META_USER_FOUND: + { + /* The goto mentioned in this block should be local to this + * block if C'd allow it. + * + * They are used to "implement" a poorman's exception handling + */ + guint32 uin = -1; + char* nick = NULL; /* Nick */ + char* first = NULL; /* First name */ + char* last = NULL; /* Last name */ + char* email = NULL; + unsigned char auth = -1; + int len = 0; + guint16 x2 = -1; + guint32 x3 = -1; + proto_tree* sstree = proto_item_add_subtree(ti, ETT_ICQ_BODY_PARTS); + + /* Skip over META_USER header */ + left -= 3; + p += 3; + /* Get the uin */ + if (left0) { + item = g_malloc(len); + strncpy(item, p, len); + proto_tree_add_text(sstree, + offset + size - left - sizeof(guint16), + sizeof(guint16)+len, + "%s(%d): %s",*d, len, item); + g_free(item); + p+=len;left-=len; + } + d++; + } + /* Get country code */ + if (left=sizeof(guint32)) { + uin = pletohl(pd + SRV_RECV_MSG_UIN); + proto_tree_add_item_format(subtree, + hf_icq_uin, + offset + SRV_RECV_MSG_UIN, + sizeof(guint32), + uin, + "UIN: %d", uin); + left -= sizeof(guint32); + } else + return; + if (left>=(sizeof(guint16)+4*sizeof(unsigned char))) { + year = pletohs(pd + SRV_RECV_MSG_YEAR); + month = pd[SRV_RECV_MSG_MONTH]; + day = pd[SRV_RECV_MSG_DAY]; + hour = pd[SRV_RECV_MSG_HOUR]; + minute = pd[SRV_RECV_MSG_MINUTE]; + + proto_tree_add_text(subtree, + offset + SRV_RECV_MSG_YEAR, + sizeof(guint16) + 4*sizeof(unsigned char), + "Time: %d-%d-%d %02d:%02d", + day, month, year, hour, minute); + + left -= (sizeof(guint16)+4*sizeof(unsigned char)); + } else + return; + icqv5_decode_msgType(subtree, + pd + SRV_RECV_MSG_MSG_TYPE, + offset + SRV_RECV_MSG_MSG_TYPE, + left); + } +} + /* * Dissect all the v5 client traffic. This is encrypted, so be careful. */ @@ -808,12 +1863,14 @@ dissect_icqv5Client(const u_char *pd, "ICQv5 %s (len %d)", findClientCmd(cmd), pktsize); - icq_tree = proto_item_add_subtree(ti, ETT_CL_ICQ); - ti = proto_tree_add_text(icq_tree, - offset, - ICQ5_CL_HDRSIZE, - "Header"); - icq_header_tree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE); + icq_tree = proto_item_add_subtree(ti, ETT_ICQ); + ti = proto_tree_add_item_format(icq_tree, + hf_icq_type, + offset, + ICQ5_CL_HDRSIZE, + ICQ5_client, + "Header"); + icq_header_tree = proto_item_add_subtree(ti, ETT_ICQ_HEADER); proto_tree_add_item_format(icq_header_tree, hf_icq_sessionid, @@ -857,19 +1914,73 @@ dissect_icqv5Client(const u_char *pd, offset + ICQ5_CL_HDRSIZE, pktsize - ICQ5_CL_HDRSIZE); 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, + 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: proto_tree_add_item_format(icq_tree, hf_icq_cmd, offset+ICQ5_CL_CMD, 2, cmd, - "Command: %d (%s)", cmd, findcmd(clientCmdCode, cmd)); + "Command: %d (%s)", + cmd, findClientCmd(cmd)); + fprintf(stderr,"Missing: %s\n", findClientCmd(cmd)); break; } ti = proto_tree_add_text(icq_tree, @@ -877,7 +1988,7 @@ dissect_icqv5Client(const u_char *pd, pktsize, "Decoded packet"); icq_decode_tree = proto_item_add_subtree(ti, - ETT_CL_ICQ_DECODE); + ETT_ICQ_DECODE); proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize); } @@ -887,63 +1998,154 @@ static void dissect_icqv5Server(const u_char *pd, int offset, frame_data *fd, - proto_tree *tree) + proto_tree *tree, + guint32 pktsize) { /* Server traffic is easy, not encrypted */ proto_tree *icq_tree = NULL; + proto_tree *icq_header_tree = NULL; proto_tree *icq_decode_tree = NULL; proto_item *ti = NULL; + const u_char* decr_pd; + int changeCol = (pktsize==(guint32)-1); guint16 version, cmd; guint32 uin, sessionid; - guint32 pktsize; + guint16 seq_num1, seq_num2; + guint32 checkcode; - uin = pletohl(&pd[offset + ICQ5_SRV_UIN]); - cmd = pletohs(&pd[offset + ICQ5_SRV_CMD]); - sessionid = pletohl(&pd[offset + ICQ5_SRV_SESSIONID]); - version = pletohs(&pd[offset + ICQ_VERSION]); - pktsize = fd->pkt_len - offset; + uin = pletohl(&pd[ICQ5_SRV_UIN]); + sessionid = pletohl(&pd[ICQ5_SRV_SESSIONID]); + cmd = pletohs(&pd[ICQ5_SRV_CMD]); + version = pletohs(&pd[ICQ_VERSION]); + checkcode = pletohl(&pd[ICQ5_SRV_CHECKCODE]); + seq_num1 = pletohs(&pd[ICQ5_SRV_SEQNUM1]); + seq_num2 = pletohs(&pd[ICQ5_SRV_SEQNUM2]); + if (pktsize == -1) + pktsize = fd->pkt_len - offset; + decr_pd = pd; - if (check_col(fd, COL_INFO)) + if (changeCol && check_col(fd, COL_INFO)) col_add_fstr(fd, COL_INFO, "ICQv5 %s", findServerCmd(cmd)); if (tree) { ti = proto_tree_add_item_format(tree, proto_icq, offset, - pktsize, - NULL, - "ICQv5 Server: len %d", pktsize); + pktsize, NULL, + "ICQv5 %s (len %d)", + findServerCmd(cmd), + pktsize); - icq_tree = proto_item_add_subtree(ti, ETT_SRV_ICQ); - proto_tree_add_item_format(icq_tree, - hf_icq_cmd, - offset + ICQ5_SRV_CMD, - 2, - cmd, - "Command: %d (%s)", - cmd, findServerCmd(cmd)); - proto_tree_add_item_format(icq_tree, - hf_icq_uin, - offset+ICQ5_SRV_UIN, - 4, - uin, - "UIN: %ld", - uin); - proto_tree_add_item_format(icq_tree, + icq_tree = proto_item_add_subtree(ti, ETT_ICQ); + + ti = proto_tree_add_item_format(icq_tree, + hf_icq_type, + offset, + ICQ5_SRV_HDRSIZE, + ICQ5_server, + "Header"); + icq_header_tree = proto_item_add_subtree(ti, ETT_ICQ_HEADER); + + proto_tree_add_item_format(icq_header_tree, hf_icq_sessionid, offset+ICQ5_SRV_SESSIONID, 4, sessionid, "Session ID: 0x%08x", sessionid); + proto_tree_add_text(icq_header_tree, + offset+ICQ5_SRV_SEQNUM1, + 2, + "Seq Number1: 0x%04x", + seq_num1); + proto_tree_add_text(icq_header_tree, + offset+ICQ5_SRV_SEQNUM2, + 2, + "Seq Number2: 0x%04x", + seq_num2); + proto_tree_add_item_format(icq_header_tree, + hf_icq_uin, + offset+ICQ5_SRV_UIN, + 4, + uin, + "UIN: %ld", + uin); + proto_tree_add_item_format(icq_header_tree, + hf_icq_checkcode, + offset+ICQ5_SRV_CHECKCODE, + 4, + checkcode, + "Checkcode: 0x%08x", + checkcode); + switch (cmd) { + 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, + 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_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, + 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; + } + ti = proto_tree_add_text(icq_tree, offset, pktsize, "Decoded packet"); icq_decode_tree = proto_item_add_subtree(ti, - ETT_CL_ICQ_DECODE); - proto_tree_add_hexdump(icq_decode_tree, offset, pd+offset, pktsize); + ETT_ICQ_DECODE); + proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize); } } @@ -961,7 +2163,7 @@ void dissect_icqv5(const u_char *pd, if (unknown == 0x0L) { dissect_icqv5Client(pd, offset, fd, tree); } else { - dissect_icqv5Server(pd, offset, fd, tree); + dissect_icqv5Server(pd + offset, offset, fd, tree, (guint32) -1); } } @@ -991,6 +2193,8 @@ void proto_register_icq(void) { static hf_register_info hf[] = { + { &hf_icq_type, + {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, ""}}, { &hf_icq_uin, {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, ""}}, { &hf_icq_sessionid, diff --git a/packet.h b/packet.h index d0b3befc95..378a4003a7 100644 --- a/packet.h +++ b/packet.h @@ -1,7 +1,7 @@ /* packet.h * Definitions for packet disassembly structures and routines * - * $Id: packet.h,v 1.126 1999/11/06 01:28:50 itojun Exp $ + * $Id: packet.h,v 1.127 1999/11/06 03:08:34 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -251,10 +251,11 @@ enum { ETT_DNS_ANS, ETT_DNS_RR, ETT_EIGRP, - ETT_CL_ICQ, - ETT_CL_ICQ_DECODE, - ETT_ICQ_SUBTREE, - ETT_SRV_ICQ, + ETT_ICQ, + ETT_ICQ_DECODE, + ETT_ICQ_HEADER, + ETT_ICQ_BODY, + ETT_ICQ_BODY_PARTS, ETT_ISAKMP, ETT_ISAKMP_FLAGS, ETT_ISAKMP_PAYLOAD,