2 * Routines for ICQ packet disassembly
4 * $Id: packet-icq.c,v 1.9 1999/12/05 22:59:55 guy Exp $
6 * Ethereal - Network traffic analyzer
8 * Copyright 1999 Johan Feyaerts
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 * This file: by Kojak <kojak@bigwig.net>
27 * Decoding code ripped, reference to the original author at the
28 * appropriate place with the code itself.
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
39 #ifdef HAVE_NETINET_IN_H
40 #include <netinet/in.h>
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
59 #ifdef NEED_SNPRINTF_H
65 # include "snprintf.h"
71 static int proto_icq = -1;
72 static int hf_icq_uin =-1;
73 static int hf_icq_cmd =-1;
74 static int hf_icq_sessionid =-1;
75 static int hf_icq_checkcode =-1;
76 static int hf_icq_decode = -1;
77 static int hf_icq_type = -1;
79 static gint ett_icq = -1;
80 static gint ett_icq_header = -1;
81 static gint ett_icq_decode = -1;
82 static gint ett_icq_body = -1;
83 static gint ett_icq_body_parts = -1;
85 enum { ICQ5_client, ICQ5_server};
87 void dissect_icqv5(const u_char *pd,
93 dissect_icqv5Server(const u_char *pd,
99 /* Offsets of fields in the ICQ headers */
100 /* Can be 0x0002 or 0x0005 */
101 #define ICQ_VERSION 0x00
102 /* Is either one (server) or four (client) bytes long */
103 /* Client header offsets */
104 #define ICQ5_UNKNOWN 0x02
105 #define ICQ5_CL_UIN 0x06
106 #define ICQ5_CL_SESSIONID 0x0a
107 #define ICQ5_CL_CMD 0x0e
108 #define ICQ5_CL_SEQNUM1 0x10
109 #define ICQ5_CL_SEQNUM2 0x12
110 #define ICQ5_CL_CHECKCODE 0x14
111 #define ICQ5_CL_PARAM 0x18
112 #define ICQ5_CL_HDRSIZE 0x18
114 /* Server header offsets */
115 #define ICQ5_SRV_SESSIONID 0x03
116 #define ICQ5_SRV_CMD 0x07
117 #define ICQ5_SRV_SEQNUM1 0x09
118 #define ICQ5_SRV_SEQNUM2 0x0b
119 #define ICQ5_SRV_UIN 0x0d
120 #define ICQ5_SRV_CHECKCODE 0x11
121 #define ICQ5_SRV_PARAM 0x15
122 #define ICQ5_SRV_HDRSIZE 0x15
124 typedef struct _cmdcode {
129 #define SRV_ACK 0x000a
131 #define SRV_GO_AWAY 0x0028
133 #define SRV_NEW_UIN 0x0046
135 /* LOGIN_REPLY is very scary. It has a lot of fields that are undocumented
136 * Only the IP field makes sense */
137 #define SRV_LOGIN_REPLY 0x005a
138 #define SRV_LOGIN_REPLY_IP 0x000c
140 #define SRV_BAD_PASS 0x0064
142 #define SRV_USER_ONLINE 0x006e
143 #define SRV_USER_ONL_UIN 0x0000
144 #define SRV_USER_ONL_IP 0x0004
145 #define SRV_USER_ONL_PORT 0x0008
146 #define SRV_USER_ONL_REALIP 0x000c
147 #define SRV_USER_ONL_X1 0x0010
148 #define SRV_USER_ONL_STATUS 0x0013
149 #define SRV_USER_ONL_X2 0x0015
151 #define SRV_USER_OFFLINE 0x0078
152 #define SRV_USER_OFFLINE_UIN 0x0000
154 #define SRV_MULTI 0x0212
155 #define SRV_MULTI_NUM 0x0000
157 #define SRV_META_USER 0x03de
158 #define SRV_META_USER_SUBCMD 0x0000
159 #define SRV_META_USER_RESULT 0x0002
160 #define SRV_META_USER_DATA 0x0003
162 #define SRV_UPDATE_SUCCESS 0x01e0
164 #define SRV_UPDATE_FAIL 0x01ea
167 * ICQv5 SRV_META_USER subcommands
169 #define META_EX_USER_FOUND 0x0190
170 #define META_USER_FOUND 0x019a
171 #define META_ABOUT 0x00e6
172 #define META_USER_INFO 0x00c8
174 #define SRV_RECV_MESSAGE 0x00dc
175 #define SRV_RECV_MSG_UIN 0x0000
176 #define SRV_RECV_MSG_YEAR 0x0004
177 #define SRV_RECV_MSG_MONTH 0x0006
178 #define SRV_RECV_MSG_DAY 0x0007
179 #define SRV_RECV_MSG_HOUR 0x0008
180 #define SRV_RECV_MSG_MINUTE 0x0009
181 #define SRV_RECV_MSG_MSG_TYPE 0x000a
183 #define SRV_RAND_USER 0x024e
184 #define SRV_RAND_USER_UIN 0x0000
185 #define SRV_RAND_USER_IP 0x0004
186 #define SRV_RAND_USER_PORT 0x0008
187 #define SRV_RAND_USER_REAL_IP 0x000c
188 #define SRV_RAND_USER_CLASS 0x0010
189 #define SRV_RAND_USER_X1 0x0011
190 #define SRV_RAND_USER_STATUS 0x0015
191 #define SRV_RAND_USER_TCP_VER 0x0019
193 /* This message has the same structure as cmd_send_msg */
194 #define SRV_SYS_DELIVERED_MESS 0x0104
196 cmdcode serverMetaSubCmdCode[] = {
197 { "META_USER_FOUND", META_USER_FOUND },
198 { "META_EX_USER_FOUND", META_EX_USER_FOUND },
199 { "META_ABOUT", META_ABOUT },
200 { "META_USER_INFO", META_USER_INFO },
204 cmdcode serverCmdCode[] = {
205 { "SRV_ACK", SRV_ACK },
206 { "SRV_GO_AWAY", SRV_GO_AWAY },
207 { "SRV_NEW_UIN", SRV_NEW_UIN },
208 { "SRV_LOGIN_REPLY", SRV_LOGIN_REPLY },
209 { "SRV_BAD_PASS", SRV_BAD_PASS },
210 { "SRV_USER_ONLINE", SRV_USER_ONLINE },
211 { "SRV_USER_OFFLINE", SRV_USER_OFFLINE },
212 { "SRV_QUERY", 130 },
213 { "SRV_USER_FOUND", 140 },
214 { "SRV_END_OF_SEARCH", 160 },
215 { "SRV_NEW_USER", 180 },
216 { "SRV_UPDATE_EXT", 200 },
217 { "SRV_RECV_MESSAGE", SRV_RECV_MESSAGE },
219 { "SRV_NOT_CONNECTED", 240 },
220 { "SRV_TRY_AGAIN", 250 },
221 { "SRV_SYS_DELIVERED_MESS", SRV_SYS_DELIVERED_MESS },
222 { "SRV_INFO_REPLY", 280 },
223 { "SRV_EXT_INFO_REPLY", 290 },
224 { "SRV_STATUS_UPDATE", 420 },
225 { "SRV_SYSTEM_MESSAGE", 450 },
226 { "SRV_UPDATE_SUCCESS", SRV_UPDATE_SUCCESS },
227 { "SRV_UPDATE_FAIL", SRV_UPDATE_FAIL },
228 { "SRV_AUTH_UPDATE", 500 },
229 { "SRV_MULTI_PACKET", SRV_MULTI },
231 { "SRV_RAND_USER", SRV_RAND_USER },
232 { "SRV_META_USER", SRV_META_USER },
236 #define MSG_TEXT 0x0001
237 #define MSG_URL 0x0004
238 #define MSG_AUTH_REQ 0x0006
239 #define MSG_AUTH 0x0008
240 #define MSG_USER_ADDED 0x000c
241 #define MSG_EMAIL 0x000e
242 #define MSG_CONTACTS 0x0013
244 #define STATUS_ONLINE 0x00000000
245 #define STATUS_AWAY 0x00000001
246 #define STATUS_DND 0x00000013
247 #define STATUS_INVISIBLE 0x00000100
248 #define STATUS_OCCUPIED 0x00000010
249 #define STATUS_NA 0x00000004
250 #define STATUS_CHAT 0x00000020
252 /* Offsets for all packets measured from the start of the payload; i.e.
253 * with the ICQ header removed
255 #define CMD_ACK 0x000a
256 #define CMD_ACK_RANDOM 0x0000
258 #define CMD_SEND_MSG 0x010E
259 #define CMD_SEND_MSG_RECV_UIN 0x0000
260 #define CMD_SEND_MSG_MSG_TYPE 0x0004
261 #define CMD_SEND_MSG_MSG_LEN 0x0006
262 #define CMD_SEND_MSG_MSG_TEXT 0x0008
263 /* The rest of the packet should be a null-term string */
265 #define CMD_LOGIN 0x03E8
266 #define CMD_LOGIN_TIME 0x0000
267 #define CMD_LOGIN_PORT 0x0004
268 #define CMD_LOGIN_PASSLEN 0x0008
269 #define CMD_LOGIN_PASSWD 0x000A
270 /* The password is variable length; so when we've decoded the passwd,
271 * the structure starts counting at 0 again.
273 #define CMD_LOGIN_IP 0x0004
274 #define CMD_LOGIN_STATUS 0x0009
276 #define CMD_CONTACT_LIST 0x0406
277 #define CMD_CONTACT_LIST_NUM 0x0000
279 #define CMD_USER_META 0x064a
281 #define CMD_REG_NEW_USER 0x03fc
283 #define CMD_ACK_MESSAGES 0x0442
284 #define CMD_ACK_MESSAGES_RANDOM 0x0000
286 #define CMD_KEEP_ALIVE 0x042e
287 #define CMD_KEEP_ALIVE_RANDOM 0x0000
289 #define CMD_SEND_TEXT_CODE 0x0438
290 #define CMD_SEND_TEXT_CODE_LEN 0x0000
291 #define CMD_SEND_TEXT_CODE_TEXT 0x0002
293 #define CMD_MSG_TO_NEW_USER 0x0456
295 #define CMD_QUERY_SERVERS 0x04ba
297 #define CMD_QUERY_ADDONS 0x04c4
299 #define CMD_STATUS_CHANGE 0x04d8
300 #define CMD_STATUS_CHANGE_STATUS 0x0000
302 #define CMD_ADD_TO_LIST 0x053c
303 #define CMD_ADD_TO_LIST_UIN 0x0000
305 #define CMD_RAND_SEARCH 0x056e
306 #define CMD_RAND_SEARCH_GROUP 0x0000
308 #define CMD_META_USER 0x064a
310 cmdcode msgTypeCode[] = {
311 { "MSG_TEXT", MSG_TEXT },
312 { "MSG_URL", MSG_URL },
313 { "MSG_AUTH_REQ", MSG_AUTH_REQ },
314 { "MSG_AUTH", MSG_AUTH },
315 { "MSG_USER_ADDED", MSG_USER_ADDED},
316 { "MSG_EMAIL", MSG_EMAIL},
317 { "MSG_CONTACTS", MSG_CONTACTS},
321 cmdcode statusCode[] = {
322 { "ONLINE", STATUS_ONLINE },
323 { "AWAY", STATUS_AWAY },
324 { "DND", STATUS_DND },
325 { "INVISIBLE", STATUS_INVISIBLE },
326 { "OCCUPIED", STATUS_OCCUPIED },
328 { "Free for Chat", STATUS_CHAT },
332 cmdcode clientCmdCode[] = {
333 { "CMD_ACK", CMD_ACK },
334 { "CMD_SEND_MESSAGE", CMD_SEND_MSG },
335 { "CMD_LOGIN", CMD_LOGIN },
336 { "CMD_REG_NEW_USER", CMD_REG_NEW_USER },
337 { "CMD_CONTACT_LIST", 1030 },
338 { "CMD_SEARCH_UIN", 1050 },
339 { "CMD_SEARCH_USER", 1060 },
340 { "CMD_KEEP_ALIVE", 1070 },
341 { "CMD_SEND_TEXT_CODE", CMD_SEND_TEXT_CODE },
342 { "CMD_ACK_MESSAGES", CMD_ACK_MESSAGES },
343 { "CMD_LOGIN_1", 1100 },
344 { "CMD_MSG_TO_NEW_USER", CMD_MSG_TO_NEW_USER },
345 { "CMD_INFO_REQ", 1120 },
346 { "CMD_EXT_INFO_REQ", 1130 },
347 { "CMD_CHANGE_PW", 1180 },
348 { "CMD_NEW_USER_INFO", 1190 },
349 { "CMD_UPDATE_EXT_INFO", 1200 },
350 { "CMD_QUERY_SERVERS", CMD_QUERY_SERVERS },
351 { "CMD_QUERY_ADDONS", CMD_QUERY_ADDONS },
352 { "CMD_STATUS_CHANGE", CMD_STATUS_CHANGE },
353 { "CMD_NEW_USER_1", 1260 },
354 { "CMD_UPDATE_INFO", 1290 },
355 { "CMD_AUTH_UPDATE", 1300 },
356 { "CMD_KEEP_ALIVE2", 1310 },
357 { "CMD_LOGIN_2", 1320 },
358 { "CMD_ADD_TO_LIST", CMD_ADD_TO_LIST },
359 { "CMD_RAND_SET", 1380 },
360 { "CMD_RAND_SEARCH", CMD_RAND_SEARCH },
361 { "CMD_META_USER", CMD_META_USER },
362 { "CMD_INVIS_LIST", 1700 },
363 { "CMD_VIS_LIST", 1710 },
364 { "CMD_UPDATE_LIST", 1720 },
369 * All ICQv5 decryption code thanx to Sebastien Dault (daus01@gel.usherb.ca)
373 0x59, 0x60, 0x37, 0x6B, 0x65, 0x62, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x60, 0x57, 0x5B, 0x3D,
374 0x5E, 0x34, 0x6D, 0x36, 0x50, 0x3F, 0x6F, 0x67, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x47, 0x63, 0x39,
375 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x43, 0x69, 0x48, 0x33, 0x31, 0x64, 0x35, 0x5A, 0x4A, 0x42,
376 0x56, 0x40, 0x67, 0x53, 0x41, 0x07, 0x6C, 0x49, 0x58, 0x3B, 0x4D, 0x46, 0x68, 0x43, 0x69, 0x48,
377 0x33, 0x31, 0x44, 0x65, 0x62, 0x46, 0x48, 0x53, 0x41, 0x07, 0x6C, 0x69, 0x48, 0x33, 0x51, 0x54,
378 0x5D, 0x4E, 0x6C, 0x49, 0x38, 0x4B, 0x55, 0x4A, 0x62, 0x46, 0x48, 0x33, 0x51, 0x34, 0x6D, 0x36,
379 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x63, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64, 0x35, 0x5A,
380 0x6A, 0x52, 0x6E, 0x3C, 0x51, 0x34, 0x6D, 0x36, 0x50, 0x5F, 0x5F, 0x3F, 0x4F, 0x37, 0x4B, 0x35,
381 0x5A, 0x4A, 0x62, 0x66, 0x58, 0x3B, 0x4D, 0x66, 0x58, 0x5B, 0x5D, 0x4E, 0x6C, 0x49, 0x58, 0x3B,
382 0x4D, 0x66, 0x58, 0x3B, 0x4D, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64,
383 0x55, 0x6A, 0x32, 0x3E, 0x44, 0x45, 0x52, 0x6E, 0x3C, 0x31, 0x64, 0x55, 0x6A, 0x52, 0x4E, 0x6C,
384 0x69, 0x48, 0x53, 0x61, 0x4C, 0x39, 0x30, 0x6F, 0x47, 0x63, 0x59, 0x60, 0x57, 0x5B, 0x3D, 0x3E,
385 0x64, 0x35, 0x3A, 0x3A, 0x5A, 0x6A, 0x52, 0x4E, 0x6C, 0x69, 0x48, 0x53, 0x61, 0x6C, 0x49, 0x58,
386 0x3B, 0x4D, 0x46, 0x68, 0x63, 0x39, 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x67, 0x53, 0x41, 0x25, 0x41,
387 0x3C, 0x51, 0x54, 0x3D, 0x5E, 0x54, 0x5D, 0x4E, 0x4C, 0x39, 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F,
388 0x47, 0x43, 0x69, 0x48, 0x33, 0x51, 0x54, 0x5D, 0x6E, 0x3C, 0x31, 0x64, 0x35, 0x5A, 0x00, 0x00 };
391 findcmd(cmdcode* c, int num)
395 while (p->descr != NULL) {
396 if (p->code == num) {
401 snprintf(buf, sizeof(buf), "(%x)", num);
408 return findcmd(msgTypeCode, num);
414 return findcmd(serverMetaSubCmdCode, num);
418 findClientCmd(int num)
420 return findcmd(clientCmdCode, num);
424 findServerCmd(int num)
426 return findcmd(serverCmdCode, num);
432 return findcmd(statusCode, num);
436 proto_tree_add_hexdump(proto_tree* t,
444 int done = 0, line = 0;
452 for (i=0;i<line;i++) {
455 for (n = i * 16; n < (i+1)*16; n++) {
456 added = sprintf(buf+done, "%02x", data[n]);
458 added += sprintf(buf + done + added, " ");
460 added += sprintf(buf + done + added, " ");
463 for (n = i * 16; n < (i+1)*16; n++) {
464 if (isprint(data[n]))
465 added = sprintf(buf + done, "%c", data[n]);
467 added = sprintf(buf + done, ".");
470 proto_tree_add_text(t,
477 for (n = line * 16 ; n < size ; n++) {
478 added = sprintf(buf+done, "%02x", data[n]);
480 added += sprintf(buf + done + added, " ");
482 added += sprintf(buf + done + added, " ");
485 for (n = size ; (n%16)!=0;n++) {
488 added += sprintf(buf + done + added, " ");
490 added += sprintf(buf + done + added, " ");
493 for (n = line * 16; n < (line+1)*16; n++) {
496 if (isprint(data[n]))
497 added = sprintf(buf + done, "%c", data[n]);
499 added = sprintf(buf + done, ".");
501 added = sprintf(buf + done, " ");
505 proto_tree_add_text(t,
513 get_v5key(const u_char* pd, int len)
515 guint32 a1, a2, a3, a4, a5;
516 guint32 code, check, key;
518 code = pletohl(&pd[ICQ5_CL_CHECKCODE]);
520 a1 = code & 0x0001f000;
521 a2 = code & 0x07c007c0;
522 a3 = code & 0x003e0001;
523 a4 = code & 0xf8000000;
524 a5 = code & 0x0000083e;
532 check = a5 + a1 + a2 + a3 + a4;
533 key = len * 0x68656C6C;
539 decrypt_v5(u_char *bfr, guint32 size,guint32 key)
543 for (i=0x0a; i < size+3; i+=4 ) {
544 k = key+table_v5[i&0xff];
546 bfr[i] ^= (u_char)(k & 0xff);
547 bfr[i+1] ^= (u_char)((k & 0xff00)>>8);
550 bfr[i+2] ^= (u_char)((k & 0xff0000)>>16);
551 bfr[i+3] ^= (u_char)((k & 0xff000000)>>24);
557 dissect_icqv2(const u_char *pd,
562 /* Not really implemented yet */
563 if (check_col(fd, COL_PROTOCOL)) {
564 col_add_str(fd, COL_PROTOCOL, "ICQv2 (UDP)");
566 if (check_col(fd, COL_INFO)) {
567 col_add_str(fd, COL_INFO, "ICQ Version 2 protocol");
572 * Find first occurrence of ch in buf
573 * Buf is max size big.
576 strnchr(const u_char* buf, u_char ch, int size)
579 u_char* p = (u_char*) buf;
580 for (i=0;(*p) && (*p!=ch) && (i<size); p++, i++)
582 if ((*p == '\0') || (i>=size))
588 * The packet at pd has a (len, string) pair.
589 * Copy the string to a buffer, and display it in the tree.
590 * Observe any limits you might cross.
592 * If anything is wrong, return -1, since -1 is not a valid string
593 * length. Else, return the number of chars processed.
596 proto_add_icq_attr(proto_tree* tree, /* The tree to add to */
597 const char* pd, /* Pointer to the field */
598 const int offset, /* Offset from the start of packet */
599 const int size, /* The number of bytes left in pd */
600 char* descr) /* The description to use in the tree */
606 if (size<sizeof(guint16))
609 left -= sizeof(guint16);
611 proto_tree_add_text(tree,
618 data = g_malloc(len);
620 strncpy(data, pd + sizeof(guint16), len);
621 data[len - 1] = '\0';
623 proto_tree_add_text(tree,
625 sizeof(guint16) + len,
626 "%s[%d]: %s", descr, len, data);
629 return len + sizeof(guint16);
633 icqv5_decode_msgType(proto_tree* tree,
634 const unsigned char* pd, /* From start of messageType */
638 proto_item* ti = NULL;
639 proto_tree* subtree = NULL;
641 char *msgText = NULL;
642 guint16 msgType = -1;
645 static char* auth_req_field_descr[] = {
652 static char* emain_field_descr[] = {
661 enum {OFF_MSG_TYPE=0,
666 if (left >= sizeof(guint16)) {
667 msgType = pletohs(pd + OFF_MSG_TYPE);
668 left -= sizeof(guint16);
670 if (left >= sizeof(guint16)) {
671 msgLen = pletohs(pd + OFF_MSG_LEN);
672 left -= sizeof(guint16);
675 ti = proto_tree_add_text(tree,
678 "Type: %d (%s)", msgType, findMsgType(msgType));
679 /* Create a new subtree */
680 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
683 case 0xffff: /* Field unknown */
686 fprintf(stderr, "Unknown msgType: %d (%04x)\n", msgType, msgType);
689 msgText = g_malloc(left + 1);
690 strncpy(msgText, pd + OFF_MSG_TEXT, left);
691 msgText[left] = '\0';
692 proto_tree_add_text(subtree,
693 offset + OFF_MSG_TEXT,
699 /* Two parts, a description and the URL. Separeted by FE */
700 for (i=0;i<left;i++) {
701 if (pd[OFF_MSG_TEXT + i] == 0xfe)
704 msgText = g_malloc(i + 1);
705 strncpy(msgText, pd + OFF_MSG_TEXT, i);
710 proto_tree_add_text(subtree,
711 offset + OFF_MSG_TEXT,
713 "Description: %s", msgText);
716 msgText = g_realloc(msgText, left - i);
717 strncpy(msgText, pd + OFF_MSG_TEXT + i + 1, left - i - 1);
718 msgText[left - i] = '\0';
719 proto_tree_add_text(subtree,
720 offset + OFF_MSG_TEXT,
729 for (n = 0; n < 6; n++) {
731 (i<left) && (pd[OFF_MSG_TEXT+i]!=0xfe);
735 msgText = g_realloc(msgText, i-j);
736 strncpy(msgText, pd + OFF_MSG_TEXT + j, i - j - 1);
737 msgText[i-j-1] = '\0';
738 proto_tree_add_text(subtree,
739 offset + OFF_MSG_TEXT + j,
741 "%s: %s", emain_field_descr[n], msgText);
743 proto_tree_add_text(subtree,
744 offset + OFF_MSG_TEXT + j,
746 "%s: %s", emain_field_descr[n], "(empty)");
756 /* Three bytes, first is a char signifying success */
757 unsigned char auth_suc = pd[OFF_MSG_LEN];
758 guint16 x1 = pd[OFF_MSG_LEN+1];
759 proto_tree_add_text(subtree,
760 offset + OFF_MSG_LEN,
762 "Authorization: (%d) %s",auth_suc,
763 (auth_suc==0)?"Denied":"Allowed");
764 proto_tree_add_text(subtree,
765 offset + OFF_MSG_LEN + 1,
771 /* Six parts, separated by FE */
774 msgText = g_malloc(64);
775 for (n = 0; n < 6 && i<left; n++) {
776 while (i<left && pd[OFF_MSG_TEXT+i]!=0xfe)
779 /* pd[OFF_MSG_TEXT+i] == 0xfe */
781 /* Otherwise, it'd be a null string */
782 msgText = g_realloc(msgText, i - j);
783 strncpy(msgText, pd + OFF_MSG_TEXT + j, i-j);
785 proto_tree_add_text(subtree,
786 offset + OFF_MSG_TEXT + j,
788 "%s: %s", auth_req_field_descr[n], msgText);
790 proto_tree_add_text(subtree,
791 offset + OFF_MSG_TEXT + j,
793 "%s: %s", auth_req_field_descr[n], "(null)");
796 /* i and j point after the 0xfe character */
804 /* Four parts, separated by FE */
807 /* This is necessary, because g_realloc does not behave like
808 * g_malloc if the first parameter == NULL */
809 msgText = g_malloc(64);
810 for (n = 0; n < 4 && i<left; n++) {
811 while (i<left && pd[OFF_MSG_TEXT+i]!=0xfe)
814 /* pd[OFF_MSG_TEXT+i] == 0xfe */
816 /* Otherwise, it'd be a null string */
817 msgText = g_realloc(msgText, i - j);
818 strncpy(msgText, pd + OFF_MSG_TEXT + j, i-j);
820 proto_tree_add_text(subtree,
821 offset + OFF_MSG_TEXT + j,
823 "%s: %s", auth_req_field_descr[n], msgText);
825 proto_tree_add_text(subtree,
826 offset + OFF_MSG_TEXT + j,
828 "%s: %s", auth_req_field_descr[n], "(null)");
831 /* i and j point after the 0xfe character */
839 u_char* p = (u_char*) &pd[OFF_MSG_TEXT];
841 int sz = 0; /* Size of the current element */
842 int n = 0; /* The nth element */
843 int done = 0; /* Number of chars processed */
844 u_char* msgText2 = NULL;
846 /* Create a new subtree */
847 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
849 p = strnchr(pprev, 0xfe, left);
852 sz = (int)(p - pprev);
855 msgText = g_realloc(msgText, sz+1);
856 strncpy(msgText, pprev, sz);
860 /* The first element is the number of Nick/UIN pairs follow */
861 proto_tree_add_text(subtree,
862 offset + OFF_MSG_TEXT + done,
864 "Number of pairs: %s", msgText);
866 } else if (p!=NULL) {
870 p = strnchr(pprev, 0xfe, left);
872 sz = (int)(p - pprev);
875 msgText2 = g_malloc(sz+1);
876 strncpy(msgText2, pprev, sz);
879 proto_tree_add_text(subtree,
880 offset + OFF_MSG_TEXT + done,
882 "%s:%s", msgText, msgText2);
896 /*********************************
900 *********************************/
902 icqv5_cmd_ack(proto_tree* tree,/* Tree to put the data in */
903 const u_char* pd, /* Packet content */
904 int offset, /* Offset from the start of the packet to the content */
905 int size) /* Number of chars left to do */
907 guint32 random = pletohl(pd + CMD_ACK_RANDOM);
912 ti = proto_tree_add_item_format(tree,
918 subtree = proto_item_add_subtree(ti, ett_icq_body);
919 proto_tree_add_text(subtree,
920 offset + CMD_ACK_RANDOM,
922 "Random: 0x%08lx", random);
927 icqv5_cmd_rand_search(proto_tree* tree, /* Tree to put the data in */
928 const u_char* pd, /* Packet content */
929 int offset, /* Offset from the start of the packet to the content */
930 int size) /* Number of chars left to do */
932 guint16 group = pletohs(pd + CMD_RAND_SEARCH_GROUP);
936 static const char* groups[] = {
951 ti = proto_tree_add_item_format(tree,
957 subtree = proto_item_add_subtree(ti, ett_icq_body);
958 if (group>0 && (group<=sizeof(groups)/sizeof(const char*)))
959 proto_tree_add_text(subtree,
960 offset + CMD_RAND_SEARCH_GROUP,
962 "Group: (%d) %s", group, groups[group-1]);
964 proto_tree_add_text(subtree,
965 offset + CMD_RAND_SEARCH_GROUP,
967 "Group: (%d)", group);
972 icqv5_cmd_ack_messages(proto_tree* tree,/* Tree to put the data in */
973 const u_char* pd, /* Packet content */
974 int offset, /* Offset from the start of the packet to the content */
975 int size) /* Number of chars left to do */
977 guint32 random = pletohl(pd + CMD_ACK_MESSAGES_RANDOM);
982 ti = proto_tree_add_item_format(tree,
988 subtree = proto_item_add_subtree(ti, ett_icq_body);
989 proto_tree_add_text(subtree,
990 offset + CMD_ACK_MESSAGES_RANDOM,
992 "Random: 0x%08lx", random);
997 icqv5_cmd_keep_alive(proto_tree* tree,/* Tree to put the data in */
998 const u_char* pd, /* Packet content */
999 int offset, /* Offset from the start of the packet to the content */
1000 int size) /* Number of chars left to do */
1002 guint32 random = pletohl(pd + CMD_KEEP_ALIVE_RANDOM);
1003 proto_tree* subtree;
1007 ti = proto_tree_add_item_format(tree,
1013 subtree = proto_item_add_subtree(ti, ett_icq_body);
1014 proto_tree_add_text(subtree,
1015 offset + CMD_KEEP_ALIVE_RANDOM,
1017 "Random: 0x%08lx", random);
1022 icqv5_cmd_send_text_code(proto_tree* tree,/* Tree to put the data in */
1023 const u_char* pd, /* Packet content */
1024 int offset, /* Offset from the start of the packet to the content */
1025 int size) /* Number of chars left to do */
1027 proto_tree* subtree;
1032 int left = size; /* The amount of data left to analyse */
1034 if (left>=sizeof(gint16)) {
1035 len = pletohs(pd+CMD_SEND_TEXT_CODE_LEN);
1036 left -= sizeof(gint16);
1039 len = MIN(len, left);
1040 text = g_malloc(len+1);
1041 memcpy(text, pd + CMD_SEND_TEXT_CODE_TEXT, len);
1045 if (left>=sizeof(gint16)) {
1046 x1 = pletohs(pd + size - left);
1047 left -= sizeof(gint16);
1050 ti = proto_tree_add_item_format(tree,
1056 subtree = proto_item_add_subtree(ti, ett_icq_body);
1057 proto_tree_add_text(subtree,
1058 offset + CMD_SEND_TEXT_CODE_LEN,
1061 proto_tree_add_text(subtree,
1062 offset + CMD_SEND_TEXT_CODE_TEXT,
1065 proto_tree_add_text(subtree,
1066 offset + CMD_SEND_TEXT_CODE_TEXT + len,
1075 icqv5_cmd_add_to_list(proto_tree* tree,/* Tree to put the data in */
1076 const u_char* pd, /* Packet content */
1077 int offset, /* Offset from the start of the packet to the content */
1078 int size) /* Number of chars left to do */
1081 proto_tree* subtree;
1084 uin = pletohl(pd + CMD_ADD_TO_LIST);
1086 ti = proto_tree_add_item_format(tree,
1092 subtree = proto_item_add_subtree(ti, ett_icq_body);
1093 proto_tree_add_text(subtree,
1094 offset + CMD_ADD_TO_LIST_UIN,
1101 icqv5_cmd_status_change(proto_tree* tree,/* Tree to put the data in */
1102 const u_char* pd, /* Packet content */
1103 int offset, /* Offset from the start of the packet to the content */
1104 int size) /* Number of chars left to do */
1106 guint32 status = -1;
1107 proto_tree* subtree;
1110 if (size >= CMD_STATUS_CHANGE_STATUS + 4)
1111 status = pletohl(pd + CMD_STATUS_CHANGE_STATUS);
1113 ti = proto_tree_add_item_format(tree,
1119 subtree = proto_item_add_subtree(ti, ett_icq_body);
1121 proto_tree_add_text(subtree,
1122 offset + CMD_STATUS_CHANGE_STATUS,
1124 "Status: %08x (%s)", status, findStatus(status));
1129 icqv5_cmd_send_msg(proto_tree* tree,
1135 proto_tree* subtree;
1137 guint32 receiverUIN = 0xffffffff;
1138 guint16 msgType = 0xffff;
1139 guint16 msgLen = 0xffff;
1140 int left = size; /* left chars to do */
1144 receiverUIN = pletohl(pd + CMD_SEND_MSG_RECV_UIN);
1148 msgType = pletohs(pd + CMD_SEND_MSG_MSG_TYPE);
1152 msgLen = pletohs(pd + CMD_SEND_MSG_MSG_LEN);
1156 ti = proto_tree_add_item_format(tree,
1162 subtree = proto_item_add_subtree(ti, ett_icq_body);
1163 proto_tree_add_text(subtree,
1164 offset + CMD_SEND_MSG_RECV_UIN,
1166 "Receiver UIN: %ld", receiverUIN);
1167 proto_tree_add_text(subtree,
1168 offset + CMD_SEND_MSG_MSG_LEN,
1170 "Length: %d", msgLen);
1172 icqv5_decode_msgType(subtree,
1173 pd + CMD_SEND_MSG_MSG_TYPE,
1174 offset + CMD_SEND_MSG_MSG_TYPE,
1175 left+4); /* There are 4 bytes more... */
1180 icqv5_cmd_login(proto_tree* tree,
1186 proto_tree* subtree;
1187 time_t theTime = -1;
1189 guint32 passwdLen = -1;
1190 char* password = NULL;
1191 const u_char *ipAddrp = NULL;
1192 guint32 status = -1;
1193 guint32 left = size;
1196 theTime = pletohl(pd + CMD_LOGIN_TIME);
1199 port = pletohl(pd + CMD_LOGIN_PORT);
1202 passwdLen = pletohs(pd + CMD_LOGIN_PASSLEN);
1204 if (left>=10+passwdLen) {
1205 password = g_malloc(passwdLen + 1);
1206 strncpy(password, pd + CMD_LOGIN_PASSWD, passwdLen);
1207 password[passwdLen] = '\0';
1210 if (left>=10+passwdLen+CMD_LOGIN_IP+4) {
1211 ipAddrp = pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP;
1213 if (left>=10+passwdLen+CMD_LOGIN_STATUS+4) {
1214 status = pletohs(pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS);
1217 ti = proto_tree_add_item_format(tree,
1223 subtree = proto_item_add_subtree(ti, ett_icq_body);
1225 proto_tree_add_text(subtree,
1226 offset + CMD_LOGIN_TIME,
1228 "Time: %d = %s", theTime, ctime(&theTime));
1230 proto_tree_add_text(subtree,
1231 offset + CMD_LOGIN_PORT,
1234 if ((passwdLen!=-1) && (password!=NULL))
1235 proto_tree_add_text(subtree,
1236 offset + CMD_LOGIN_PASSLEN,
1238 "Passwd: %s", password);
1240 proto_tree_add_text(subtree,
1241 offset + CMD_LOGIN_PASSWD + CMD_LOGIN_IP,
1243 "IP: %s", ip_to_str(ipAddrp));
1245 proto_tree_add_text(subtree,
1246 offset + CMD_LOGIN_PASSWD + CMD_LOGIN_IP,
1248 "Status: %s", findStatus(status));
1255 icqv5_cmd_contact_list(proto_tree* tree,
1260 proto_tree* subtree;
1262 unsigned char num = -1;
1265 const u_char* p = NULL;
1267 if (size >= CMD_CONTACT_LIST_NUM + 1)
1268 num = pd[CMD_CONTACT_LIST_NUM];
1271 ti = proto_tree_add_item_format(tree,
1277 subtree = proto_item_add_subtree(ti, ett_icq_body);
1278 proto_tree_add_text(subtree,
1279 offset + CMD_CONTACT_LIST,
1281 "Number of uins: %d", num);
1283 * A sequence of num times UIN follows
1285 offset += (CMD_CONTACT_LIST_NUM + 1);
1287 p = &pd[CMD_CONTACT_LIST_NUM + 1];
1288 for (i = 0; (i<num) && (left>0);i++) {
1291 proto_tree_add_text(subtree,
1294 "UIN[%d]: %ld",i,uin);
1304 icqv5_cmd_no_params(proto_tree* tree,/* Tree to put the data in */
1305 const u_char* pd, /* Packet content */
1306 int offset, /* Offset from the start of the packet to the content */
1307 int size, /* Number of chars left to do */
1310 proto_tree* subtree;
1314 ti = proto_tree_add_item_format(tree,
1320 subtree = proto_item_add_subtree(ti, ett_icq_body);
1321 proto_tree_add_text(subtree,
1328 /**********************
1332 **********************
1335 icqv5_srv_no_params(proto_tree* tree,/* Tree to put the data in */
1336 const u_char* pd, /* Packet content */
1337 int offset, /* Offset from the start of the packet to the content */
1338 int size, /* Number of chars left to do */
1341 proto_tree* subtree;
1345 ti = proto_tree_add_item_format(tree,
1351 subtree = proto_item_add_subtree(ti, ett_icq_body);
1352 proto_tree_add_text(subtree,
1360 icqv5_srv_login_reply(proto_tree* tree,/* Tree to put the data in */
1361 const u_char* pd, /* Packet content */
1362 int offset, /* Offset from the start of the packet to the content */
1363 int size) /* Number of chars left to do */
1365 proto_tree* subtree;
1367 const u_char *ipAddrp = NULL;
1369 if (size >= SRV_LOGIN_REPLY_IP + 4)
1370 ipAddrp = &pd[SRV_LOGIN_REPLY_IP];
1373 ti = proto_tree_add_item_format(tree,
1376 SRV_LOGIN_REPLY_IP + 8,
1379 subtree = proto_item_add_subtree(ti, ett_icq_body);
1380 proto_tree_add_text(subtree,
1381 offset + SRV_LOGIN_REPLY_IP,
1383 "IP: %s", ip_to_str(ipAddrp));
1388 icqv5_srv_user_online(proto_tree* tree,/* Tree to put the data in */
1389 const u_char* pd, /* Packet content */
1390 int offset, /* Offset from the start of the packet to the content */
1391 int size) /* Number of chars left to do */
1393 proto_tree* subtree;
1396 const u_char *ipAddrp = NULL;
1398 const u_char *realipAddrp = NULL;
1399 guint32 status = -1;
1400 guint32 version = -1;
1402 if (size >= SRV_USER_ONL_UIN + 4)
1403 uin = pletohl(pd + SRV_USER_ONL_UIN);
1405 if (size >= SRV_USER_ONL_IP + 4)
1406 ipAddrp = &pd[SRV_USER_ONL_IP];
1408 if (size >= SRV_USER_ONL_PORT + 4)
1409 port = pletohl(pd + SRV_USER_ONL_PORT);
1411 if (size >= SRV_USER_ONL_REALIP + 4)
1412 realipAddrp = &pd[SRV_USER_ONL_REALIP];
1414 if (size >= SRV_USER_ONL_STATUS + 2)
1415 status = pletohs(pd + SRV_USER_ONL_STATUS);
1418 * Kojak: Hypothesis is that this field might be an encoding for the
1419 * version used by the UIN that changed. To test this, I included
1420 * this line to the code.
1422 if (size >= SRV_USER_ONL_X2 + 4)
1423 version = pletohl(pd + SRV_USER_ONL_X2);
1426 ti = proto_tree_add_item_format(tree,
1429 SRV_LOGIN_REPLY_IP + 8,
1432 subtree = proto_item_add_subtree(ti, ett_icq_body);
1433 proto_tree_add_text(subtree,
1434 offset + SRV_USER_ONL_UIN,
1437 proto_tree_add_text(subtree,
1438 offset + SRV_USER_ONL_IP,
1440 "IP: %s", ip_to_str(ipAddrp));
1441 proto_tree_add_text(subtree,
1442 offset + SRV_USER_ONL_PORT,
1445 proto_tree_add_text(subtree,
1446 offset + SRV_USER_ONL_REALIP,
1448 "RealIP: %s", ip_to_str(realipAddrp));
1449 proto_tree_add_text(subtree,
1450 offset + SRV_USER_ONL_STATUS,
1452 "Status: %s", findStatus(status));
1453 proto_tree_add_text(subtree,
1454 offset + SRV_USER_ONL_X2,
1456 "Version: %08x", version);
1461 icqv5_srv_user_offline(proto_tree* tree,/* Tree to put the data in */
1462 const u_char* pd, /* Packet content */
1463 int offset, /* Offset from the start of the packet to the content */
1464 int size) /* Number of chars left to do */
1466 proto_tree* subtree;
1470 if (size >= SRV_USER_OFFLINE + 4)
1471 uin = pletohl(&pd[SRV_USER_OFFLINE]);
1474 ti = proto_tree_add_item_format(tree,
1477 SRV_USER_OFFLINE_UIN + 4,
1480 subtree = proto_item_add_subtree(ti, ett_icq_body);
1481 proto_tree_add_text(subtree,
1482 offset + SRV_USER_OFFLINE_UIN,
1489 icqv5_srv_multi(proto_tree* tree,/* Tree to put the data in */
1490 const u_char* pd, /* Packet content */
1491 int offset, /* Offset from the start of the packet to the content */
1492 int size, /* Number of chars left to do */
1495 proto_tree* subtree;
1497 unsigned char num = -1;
1500 const u_char* p = NULL;
1502 if (size >= SRV_MULTI_NUM + 1)
1503 num = pd[SRV_MULTI_NUM];
1506 ti = proto_tree_add_item_format(tree,
1512 subtree = proto_item_add_subtree(ti, ett_icq_body);
1513 proto_tree_add_text(subtree,
1514 offset + SRV_MULTI_NUM,
1516 "Number of pkts: %d", num);
1518 * A sequence of num times ( pktsize, packetData) follows
1520 offset += (SRV_MULTI_NUM + 1);
1522 p = &pd[SRV_MULTI_NUM + 1];
1523 for (i = 0; (i<num) && (left>0);i++) {
1530 dissect_icqv5Server(p, offset, fd, subtree, pktSz);
1541 icqv5_srv_meta_user(proto_tree* tree, /* Tree to put the data in */
1542 const u_char* pd, /* Packet content */
1543 int offset, /* Offset from the start of the packet to the content */
1544 int size) /* Number of chars left to do */
1547 proto_tree* subtree = NULL;
1549 proto_tree* sstree = NULL;
1550 proto_item* ti = NULL;
1554 guint16 subcmd = -1;
1555 unsigned char result = -1;
1557 if (size>=SRV_META_USER_SUBCMD + 2)
1558 subcmd = pletohs(pd+SRV_META_USER_SUBCMD);
1559 if (size>=SRV_META_USER_RESULT + 1)
1560 result = pd[SRV_META_USER_RESULT];
1564 ti = proto_tree_add_item_format(tree,
1570 subtree = proto_item_add_subtree(ti, ett_icq_body);
1571 ti = proto_tree_add_text(subtree,
1572 offset + SRV_META_USER_SUBCMD,
1574 "%s", findSubCmd(subcmd));
1575 proto_tree_add_text(subtree,
1576 offset + SRV_META_USER_RESULT,
1578 "%s", (result==0x0a)?"Success":"Failure");
1579 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1581 ti = proto_tree_add_text(tree,
1582 offset + SRV_META_USER_SUBCMD,
1584 "%s", findSubCmd(subcmd));
1585 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1586 proto_tree_add_text(sstree,
1587 offset + SRV_META_USER_RESULT,
1589 "%s", (result==0x0a)?"Success":"Failure");
1592 /* Skip the META_USER header */
1597 case META_EX_USER_FOUND:
1599 /* This is almost the same as META_USER_FOUND,
1600 * however, there's an extra length field
1602 guint16 pktLen = -1;
1604 /* Read the lenght field */
1605 pktLen = pletohs(p);
1606 proto_tree_add_text(sstree,
1607 offset + size - left,
1609 "Length: %d", pktLen);
1611 p += sizeof(guint16); left -= sizeof(guint16);
1613 case META_USER_FOUND:
1615 /* The goto mentioned in this block should be local to this
1616 * block if C'd allow it.
1618 * They are used to "implement" a poorman's exception handling
1635 if (left<sizeof(guint32))
1638 proto_tree_add_text(sstree,
1639 offset + size - left,
1642 p+=sizeof(guint32);left-=sizeof(guint32);
1644 for ( ; *d!=NULL; d++) {
1645 len = proto_add_icq_attr(sstree,
1647 offset + size - left,
1652 p += len; left -= len;
1654 /* Get the authorize setting */
1655 if (left<sizeof(unsigned char))
1658 proto_tree_add_text(sstree,
1659 offset + size - left,
1661 "authorization: %s", (auth==0x01)?"Neccessary":"Who needs it");
1664 if (left<sizeof(guint16))
1667 proto_tree_add_text(sstree,
1668 offset + size - left,
1671 p+=sizeof(guint16);left-=sizeof(guint16);
1673 if (left<sizeof(guint32))
1676 proto_tree_add_text(sstree,
1677 offset + size - left,
1680 p+=sizeof(guint32);left-=sizeof(guint32);
1687 /* Get the about information */
1688 if (left<sizeof(guint16))
1691 p+=sizeof(guint16);left-=sizeof(guint16);
1692 if ((len<=0) || (left<len))
1694 about = g_malloc(len);
1695 strncpy(about, p, len);
1696 proto_tree_add_text(sstree,
1697 offset + size - left,
1698 sizeof(guint16)+len,
1699 "About(%d): %s", len, about);
1705 case META_USER_INFO:
1707 /* The goto mentioned in this block should be local to this
1708 * block if C'd allow it.
1710 * They are used to "implement" a poorman's exception handling
1712 static const char* descr[] = {
1727 const char** d = descr;
1730 unsigned char user_timezone = -1;
1731 unsigned char auth = -1;
1735 if (left<sizeof(guint32))
1738 proto_tree_add_text(sstree,
1739 offset + size - left,
1742 p+=sizeof(guint32);left-=sizeof(guint32);
1746 * Get every field from the description
1748 while ((*d)!=NULL) {
1749 if (left<sizeof(guint16))
1752 p+=sizeof(guint16);left-=sizeof(guint16);
1753 if ((len<0) || (left<len))
1756 item = g_malloc(len);
1757 strncpy(item, p, len);
1758 proto_tree_add_text(sstree,
1759 offset + size - left - sizeof(guint16),
1760 sizeof(guint16)+len,
1761 "%s(%d): %s",*d, len, item);
1767 /* Get country code */
1768 if (left<sizeof(guint16))
1770 country = pletohs(p);
1771 proto_tree_add_text(sstree,
1772 offset + size - left,
1774 "Countrycode: %d", country);
1775 p+=sizeof(guint16); left-=sizeof(guint16);
1776 /* Get the timezone setting */
1777 if (left<sizeof(unsigned char))
1780 proto_tree_add_text(sstree,
1781 offset + size - left,
1782 sizeof(unsigned char),
1783 "Timezone: %d", user_timezone);
1785 /* Get the authorize setting */
1786 if (left<sizeof(unsigned char))
1789 proto_tree_add_text(sstree,
1790 offset + size - left,
1791 sizeof(unsigned char),
1792 "Authorization: (%d) %s",
1793 auth, (auth==0)?"No":"Yes");
1795 /* Get the webaware setting */
1796 if (left<sizeof(unsigned char))
1799 proto_tree_add_text(sstree,
1800 offset + size - left,
1801 sizeof(unsigned char),
1802 "Webaware: (%d) %s",
1803 auth, (auth==0)?"No":"Yes");
1805 /* Get the authorize setting */
1806 if (left<sizeof(unsigned char))
1809 proto_tree_add_text(sstree,
1810 offset + size - left,
1811 sizeof(unsigned char),
1813 auth, (auth==0)?"No":"Yes");
1818 /* This information is already printed in the tree */
1819 fprintf(stderr, "Meta subcmd: %04x\n", subcmd);
1826 icqv5_srv_recv_message(proto_tree* tree, /* Tree to put the data in */
1827 const u_char* pd, /* Packet content */
1828 int offset, /* Offset from the start of the packet to the content */
1829 int size) /* Number of chars left to do */
1831 proto_tree* subtree = NULL;
1832 proto_item* ti = NULL;
1836 unsigned char month = -1;
1837 unsigned char day = -1;
1838 unsigned char hour = -1;
1839 unsigned char minute = -1;
1842 ti = proto_tree_add_item_format(tree,
1848 subtree = proto_item_add_subtree(ti, ett_icq_body);
1849 if (left>=sizeof(guint32)) {
1850 uin = pletohl(pd + SRV_RECV_MSG_UIN);
1851 proto_tree_add_item_format(subtree,
1853 offset + SRV_RECV_MSG_UIN,
1857 left -= sizeof(guint32);
1860 if (left>=(sizeof(guint16)+4*sizeof(unsigned char))) {
1861 year = pletohs(pd + SRV_RECV_MSG_YEAR);
1862 month = pd[SRV_RECV_MSG_MONTH];
1863 day = pd[SRV_RECV_MSG_DAY];
1864 hour = pd[SRV_RECV_MSG_HOUR];
1865 minute = pd[SRV_RECV_MSG_MINUTE];
1867 proto_tree_add_text(subtree,
1868 offset + SRV_RECV_MSG_YEAR,
1869 sizeof(guint16) + 4*sizeof(unsigned char),
1870 "Time: %d-%d-%d %02d:%02d",
1871 day, month, year, hour, minute);
1873 left -= (sizeof(guint16)+4*sizeof(unsigned char));
1876 icqv5_decode_msgType(subtree,
1877 pd + SRV_RECV_MSG_MSG_TYPE,
1878 offset + SRV_RECV_MSG_MSG_TYPE,
1884 icqv5_srv_rand_user(proto_tree* tree, /* Tree to put the data in */
1885 const u_char* pd, /* Packet content */
1886 int offset, /* Offset from the start of the packet to the content */
1887 int size) /* Number of chars left to do */
1889 proto_tree* subtree = NULL;
1890 proto_item* ti = NULL;
1892 const unsigned char* IP = NULL;
1894 const unsigned char* realIP = NULL;
1895 unsigned char commClass = -1;
1901 ti = proto_tree_add_item_format(tree,
1904 SRV_RAND_USER_TCP_VER + 2,
1907 subtree = proto_item_add_subtree(ti, ett_icq_body);
1909 if (left<sizeof(guint32))
1911 uin = pletohl(pd + SRV_RAND_USER_UIN);
1912 proto_tree_add_text(subtree,
1913 offset + SRV_RAND_USER_UIN,
1916 left -= sizeof(guint32);
1918 if (left<sizeof(guint32))
1920 IP = pd + SRV_RAND_USER_IP;
1921 proto_tree_add_text(subtree,
1922 offset + SRV_RAND_USER_IP,
1924 "IP: %s", ip_to_str(IP));
1925 left -= sizeof(guint32);
1926 /* guint32 portNum */
1927 if (left<sizeof(guint32))
1929 port = pletohs(pd + SRV_RAND_USER_PORT);
1930 proto_tree_add_text(subtree,
1931 offset + SRV_RAND_USER_UIN,
1934 left -= sizeof(guint32);
1935 /* guint32 realIP */
1936 if (left<sizeof(guint32))
1938 realIP = pd + SRV_RAND_USER_REAL_IP;
1939 proto_tree_add_text(subtree,
1940 offset + SRV_RAND_USER_REAL_IP,
1942 "RealIP: %s", ip_to_str(realIP));
1943 left -= sizeof(guint32);
1944 /* guit16 Communication Class */
1945 if (left<sizeof(unsigned char))
1947 commClass = pd[SRV_RAND_USER_CLASS];
1948 proto_tree_add_text(subtree,
1949 offset + SRV_RAND_USER_CLASS,
1950 sizeof(unsigned char),
1951 "Class: %s", (commClass!=4)?"User to User":"Through Server");
1952 left -= sizeof(unsigned char);
1953 /* guint32 status */
1954 if (left<sizeof(guint32))
1956 status = pletohs(pd + SRV_RAND_USER_STATUS);
1957 proto_tree_add_text(subtree,
1958 offset + SRV_RAND_USER_STATUS,
1960 "Status: (%ld) %s", status, findStatus(status));
1961 /* guint16 tcpVersion */
1962 if (left<sizeof(guint16))
1964 tcpVer = pletohs(pd + SRV_RAND_USER_TCP_VER);
1965 proto_tree_add_text(subtree,
1966 offset + SRV_RAND_USER_TCP_VER,
1968 "TCPVersion: %d", tcpVer);
1969 left -= sizeof(guint16);
1974 * Dissect all the v5 client traffic. This is encrypted, so be careful.
1977 dissect_icqv5Client(const u_char *pd,
1982 proto_tree *icq_tree = NULL;
1983 proto_tree *icq_header_tree = NULL;
1984 proto_tree *icq_decode_tree = NULL;
1985 proto_item *ti = NULL;
1987 guint16 version = -1, cmd = -1;
1988 guint16 seqnum1 = 0 , seqnum2 = 0;
1989 guint32 uin = -1, sessionid = -1;
1991 guint16 pktsize = -1; /* The size of the ICQ content */
1992 u_char decr_pd[1600]; /* Decrypted content, size should be dynamic */
1994 pktsize = fd->pkt_len - offset;
1995 /* First copy the memory, we don't want to overwrite the old content */
1996 memcpy(decr_pd, &pd[offset], pktsize);
1997 if (fd->pkt_len > fd->cap_len) {
1998 pktsize -= (fd->pkt_len - fd->cap_len);
2001 key = get_v5key(decr_pd, pktsize);
2002 decrypt_v5(decr_pd, pktsize, key);
2004 /* This information only makes sense in the decrypted version */
2005 uin = pletohl(&decr_pd[ICQ5_CL_UIN]);
2006 cmd = pletohs(&decr_pd[ICQ5_CL_CMD]);
2007 sessionid = pletohl(&decr_pd[ICQ5_CL_SESSIONID]);
2008 version = pletohs(&decr_pd[ICQ_VERSION]);
2009 seqnum1 = pletohs(&decr_pd[ICQ5_CL_SEQNUM1]);
2010 seqnum2 = pletohs(&decr_pd[ICQ5_CL_SEQNUM2]);
2012 if (check_col(fd, COL_INFO))
2013 col_add_fstr(fd, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
2017 ti = proto_tree_add_item_format(tree,
2021 "ICQv5 %s (len %d)",
2024 icq_tree = proto_item_add_subtree(ti, ett_icq);
2025 ti = proto_tree_add_item_format(icq_tree,
2031 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
2033 proto_tree_add_item_format(icq_header_tree,
2035 offset+ICQ5_CL_SESSIONID,
2038 "Session ID: 0x%08x",
2040 proto_tree_add_item_format(icq_header_tree,
2042 offset+ICQ5_CL_CHECKCODE,
2047 proto_tree_add_item_format(icq_header_tree,
2052 "UIN: %ld (0x%08X)",
2054 proto_tree_add_text(icq_header_tree,
2055 offset + ICQ5_CL_SEQNUM1,
2057 "Seqnum1: 0x%04x", seqnum1);
2058 proto_tree_add_text(icq_header_tree,
2059 offset + ICQ5_CL_SEQNUM1,
2061 "Seqnum2: 0x%04x", seqnum2);
2064 icqv5_cmd_ack(icq_tree,
2065 decr_pd + ICQ5_CL_HDRSIZE,
2066 offset + ICQ5_CL_HDRSIZE,
2067 pktsize - ICQ5_CL_HDRSIZE);
2070 case CMD_MSG_TO_NEW_USER:
2071 icqv5_cmd_send_msg(icq_tree,
2072 decr_pd + ICQ5_CL_HDRSIZE,
2073 offset + ICQ5_CL_HDRSIZE,
2074 pktsize - ICQ5_CL_HDRSIZE,
2077 case CMD_RAND_SEARCH:
2078 icqv5_cmd_rand_search(icq_tree,
2079 decr_pd + ICQ5_CL_HDRSIZE,
2080 offset + ICQ5_CL_HDRSIZE,
2081 pktsize - ICQ5_CL_HDRSIZE);
2084 icqv5_cmd_login(icq_tree,
2085 decr_pd + ICQ5_CL_HDRSIZE,
2086 offset + ICQ5_CL_HDRSIZE,
2087 pktsize - ICQ5_CL_HDRSIZE);
2089 case CMD_SEND_TEXT_CODE:
2090 icqv5_cmd_send_text_code(icq_tree,
2091 decr_pd + ICQ5_CL_HDRSIZE,
2092 offset + ICQ5_CL_HDRSIZE,
2093 pktsize - ICQ5_CL_HDRSIZE);
2095 case CMD_STATUS_CHANGE:
2096 icqv5_cmd_status_change(icq_tree,
2097 decr_pd + ICQ5_CL_HDRSIZE,
2098 offset + ICQ5_CL_HDRSIZE,
2099 pktsize - ICQ5_CL_HDRSIZE);
2101 case CMD_ACK_MESSAGES:
2102 icqv5_cmd_ack_messages(icq_tree,
2103 decr_pd + ICQ5_CL_HDRSIZE,
2104 offset + ICQ5_CL_HDRSIZE,
2105 pktsize - ICQ5_CL_HDRSIZE);
2107 case CMD_KEEP_ALIVE:
2108 icqv5_cmd_keep_alive(icq_tree,
2109 decr_pd + ICQ5_CL_HDRSIZE,
2110 offset + ICQ5_CL_HDRSIZE,
2111 pktsize - ICQ5_CL_HDRSIZE);
2113 case CMD_ADD_TO_LIST:
2114 icqv5_cmd_add_to_list(icq_tree,
2115 decr_pd + ICQ5_CL_HDRSIZE,
2116 offset + ICQ5_CL_HDRSIZE,
2117 pktsize - ICQ5_CL_HDRSIZE);
2119 case CMD_CONTACT_LIST:
2120 icqv5_cmd_contact_list(icq_tree,
2121 decr_pd + ICQ5_CL_HDRSIZE,
2122 offset + ICQ5_CL_HDRSIZE,
2123 pktsize - ICQ5_CL_HDRSIZE);
2126 case CMD_REG_NEW_USER:
2127 case CMD_QUERY_SERVERS:
2128 case CMD_QUERY_ADDONS:
2129 icqv5_cmd_no_params(icq_tree,
2130 decr_pd + ICQ5_CL_HDRSIZE,
2131 offset + ICQ5_CL_HDRSIZE,
2132 pktsize - ICQ5_CL_HDRSIZE,
2136 proto_tree_add_item_format(icq_tree,
2142 cmd, findClientCmd(cmd));
2143 fprintf(stderr,"Missing: %s\n", findClientCmd(cmd));
2146 ti = proto_tree_add_text(icq_tree,
2150 icq_decode_tree = proto_item_add_subtree(ti,
2152 proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
2158 dissect_icqv5Server(const u_char *pd,
2164 /* Server traffic is easy, not encrypted */
2165 proto_tree *icq_tree = NULL;
2166 proto_tree *icq_header_tree = NULL;
2167 proto_tree *icq_decode_tree = NULL;
2168 proto_item *ti = NULL;
2169 const u_char* decr_pd;
2170 int changeCol = (pktsize==(guint32)-1);
2172 guint16 version, cmd;
2173 guint32 uin, sessionid;
2174 guint16 seq_num1, seq_num2;
2177 uin = pletohl(&pd[ICQ5_SRV_UIN]);
2178 sessionid = pletohl(&pd[ICQ5_SRV_SESSIONID]);
2179 cmd = pletohs(&pd[ICQ5_SRV_CMD]);
2180 version = pletohs(&pd[ICQ_VERSION]);
2181 checkcode = pletohl(&pd[ICQ5_SRV_CHECKCODE]);
2182 seq_num1 = pletohs(&pd[ICQ5_SRV_SEQNUM1]);
2183 seq_num2 = pletohs(&pd[ICQ5_SRV_SEQNUM2]);
2185 pktsize = fd->pkt_len - offset;
2188 if (changeCol && check_col(fd, COL_INFO))
2189 col_add_fstr(fd, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
2192 ti = proto_tree_add_item_format(tree,
2196 "ICQv5 %s (len %d)",
2200 icq_tree = proto_item_add_subtree(ti, ett_icq);
2202 ti = proto_tree_add_item_format(icq_tree,
2208 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
2210 proto_tree_add_item_format(icq_header_tree,
2212 offset+ICQ5_SRV_SESSIONID,
2215 "Session ID: 0x%08x",
2217 proto_tree_add_text(icq_header_tree,
2218 offset+ICQ5_SRV_SEQNUM1,
2220 "Seq Number1: 0x%04x",
2222 proto_tree_add_text(icq_header_tree,
2223 offset+ICQ5_SRV_SEQNUM2,
2225 "Seq Number2: 0x%04x",
2227 proto_tree_add_item_format(icq_header_tree,
2229 offset+ICQ5_SRV_UIN,
2234 proto_tree_add_item_format(icq_header_tree,
2236 offset+ICQ5_SRV_CHECKCODE,
2239 "Checkcode: 0x%08x",
2243 icqv5_srv_rand_user(icq_tree,
2244 decr_pd + ICQ5_SRV_HDRSIZE,
2245 offset + ICQ5_SRV_HDRSIZE,
2246 pktsize - ICQ5_SRV_HDRSIZE);
2248 case SRV_SYS_DELIVERED_MESS:
2249 /* The message structures are all the same. Why not run
2250 * the same routine? */
2251 icqv5_cmd_send_msg(icq_tree,
2252 decr_pd + ICQ5_SRV_HDRSIZE,
2253 offset + ICQ5_SRV_HDRSIZE,
2254 pktsize - ICQ5_SRV_HDRSIZE,
2257 case SRV_USER_ONLINE:
2258 icqv5_srv_user_online(icq_tree,
2259 decr_pd + ICQ5_SRV_HDRSIZE,
2260 offset + ICQ5_SRV_HDRSIZE,
2261 pktsize - ICQ5_SRV_HDRSIZE);
2263 case SRV_USER_OFFLINE:
2264 icqv5_srv_user_offline(icq_tree,
2265 decr_pd + ICQ5_SRV_HDRSIZE,
2266 offset + ICQ5_SRV_HDRSIZE,
2267 pktsize - ICQ5_SRV_HDRSIZE);
2269 case SRV_LOGIN_REPLY:
2270 icqv5_srv_login_reply(icq_tree,
2271 decr_pd + ICQ5_SRV_HDRSIZE,
2272 offset + ICQ5_SRV_HDRSIZE,
2273 pktsize - ICQ5_SRV_HDRSIZE);
2276 icqv5_srv_meta_user(icq_tree,
2277 decr_pd + ICQ5_SRV_HDRSIZE,
2278 offset + ICQ5_SRV_HDRSIZE,
2279 pktsize - ICQ5_SRV_HDRSIZE);
2281 case SRV_RECV_MESSAGE:
2282 icqv5_srv_recv_message(icq_tree,
2283 decr_pd + ICQ5_SRV_HDRSIZE,
2284 offset + ICQ5_SRV_HDRSIZE,
2285 pktsize - ICQ5_SRV_HDRSIZE);
2288 icqv5_srv_multi(icq_tree,
2289 decr_pd + ICQ5_SRV_HDRSIZE,
2290 offset + ICQ5_SRV_HDRSIZE,
2291 pktsize - ICQ5_SRV_HDRSIZE,
2298 case SRV_UPDATE_SUCCESS:
2299 icqv5_srv_no_params(icq_tree,
2300 decr_pd + ICQ5_SRV_HDRSIZE,
2301 offset + ICQ5_SRV_HDRSIZE,
2302 pktsize - ICQ5_SRV_HDRSIZE,
2306 proto_tree_add_item_format(icq_tree,
2308 offset + ICQ5_SRV_CMD,
2312 cmd, findServerCmd(cmd));
2313 fprintf(stderr,"Missing: %s\n", findServerCmd(cmd));
2317 ti = proto_tree_add_text(icq_tree,
2321 icq_decode_tree = proto_item_add_subtree(ti,
2323 proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
2327 void dissect_icqv5(const u_char *pd,
2332 guint32 unknown = pletohl(&pd[offset + ICQ5_UNKNOWN]);
2334 if (check_col(fd, COL_PROTOCOL))
2335 col_add_str(fd, COL_PROTOCOL, "ICQv5 (UDP)");
2336 if (check_col(fd, COL_INFO))
2337 col_add_str(fd, COL_INFO, "ICQv5 packet");
2338 if (unknown == 0x0L) {
2339 dissect_icqv5Client(pd, offset, fd, tree);
2341 dissect_icqv5Server(pd + offset, offset, fd, tree, (guint32) -1);
2345 void dissect_icq(const u_char *pd,
2352 version = pletohs(&pd[offset + ICQ_VERSION]);
2355 dissect_icqv5(pd, offset, fd, tree);
2358 dissect_icqv2(pd, offset, fd, tree);
2361 fprintf(stderr, "ICQ: Unknown version (%d)\n", version);
2366 /* registration with the filtering engine */
2368 proto_register_icq(void)
2370 static hf_register_info hf[] = {
2372 {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2374 {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, ""}},
2375 { &hf_icq_sessionid,
2376 {"SessionID", "icq.sessionid", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2378 {"Command", "icq.cmd", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2379 { &hf_icq_checkcode,
2380 {"Checkcode", "icq.checkcode", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2382 {"Decode", "icq.decode", FT_STRING, BASE_NONE, NULL, 0x0, ""}}
2384 static gint *ett[] = {
2389 &ett_icq_body_parts,
2392 proto_icq = proto_register_protocol ("ICQ Protocol", "icq");
2394 proto_register_field_array(proto_icq, hf, array_length(hf));
2396 proto_register_subtree_array(ett, array_length(ett));