2 * Routines for ICQ packet disassembly
4 * $Id: packet-icq.c,v 1.25 2001/01/03 06:55:28 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
60 # include "snprintf.h"
66 static int proto_icq = -1;
67 static int hf_icq_uin =-1;
68 static int hf_icq_cmd =-1;
69 static int hf_icq_sessionid =-1;
70 static int hf_icq_checkcode =-1;
71 static int hf_icq_decode = -1;
72 static int hf_icq_type = -1;
74 static gint ett_icq = -1;
75 static gint ett_icq_header = -1;
76 static gint ett_icq_decode = -1;
77 static gint ett_icq_body = -1;
78 static gint ett_icq_body_parts = -1;
80 #define UDP_PORT_ICQ 4000
82 enum { ICQ5_client, ICQ5_server};
84 static void dissect_icqv5(const u_char *pd,
90 dissect_icqv5Server(const u_char *pd,
96 /* Offsets of fields in the ICQ headers */
97 /* Can be 0x0002 or 0x0005 */
98 #define ICQ_VERSION 0x00
99 /* Is either one (server) or four (client) bytes long */
100 /* Client header offsets */
101 #define ICQ5_UNKNOWN 0x02
102 #define ICQ5_CL_UIN 0x06
103 #define ICQ5_CL_SESSIONID 0x0a
104 #define ICQ5_CL_CMD 0x0e
105 #define ICQ5_CL_SEQNUM1 0x10
106 #define ICQ5_CL_SEQNUM2 0x12
107 #define ICQ5_CL_CHECKCODE 0x14
108 #define ICQ5_CL_PARAM 0x18
109 #define ICQ5_CL_HDRSIZE 0x18
111 /* Server header offsets */
112 #define ICQ5_SRV_SESSIONID 0x03
113 #define ICQ5_SRV_CMD 0x07
114 #define ICQ5_SRV_SEQNUM1 0x09
115 #define ICQ5_SRV_SEQNUM2 0x0b
116 #define ICQ5_SRV_UIN 0x0d
117 #define ICQ5_SRV_CHECKCODE 0x11
118 #define ICQ5_SRV_PARAM 0x15
119 #define ICQ5_SRV_HDRSIZE 0x15
121 typedef struct _cmdcode {
126 #define SRV_ACK 0x000a
128 #define SRV_SILENT_TOO_LONG 0x001e
130 #define SRV_GO_AWAY 0x0028
132 #define SRV_NEW_UIN 0x0046
134 /* LOGIN_REPLY is very scary. It has a lot of fields that are undocumented
135 * Only the IP field makes sense */
136 #define SRV_LOGIN_REPLY 0x005a
137 #define SRV_LOGIN_REPLY_IP 0x000c
139 #define SRV_BAD_PASS 0x0064
141 #define SRV_USER_ONLINE 0x006e
142 #define SRV_USER_ONL_UIN 0x0000
143 #define SRV_USER_ONL_IP 0x0004
144 #define SRV_USER_ONL_PORT 0x0008
145 #define SRV_USER_ONL_REALIP 0x000c
146 #define SRV_USER_ONL_X1 0x0010
147 #define SRV_USER_ONL_STATUS 0x0013
148 #define SRV_USER_ONL_X2 0x0015
150 #define SRV_USER_OFFLINE 0x0078
151 #define SRV_USER_OFFLINE_UIN 0x0000
153 #define SRV_MULTI 0x0212
154 #define SRV_MULTI_NUM 0x0000
156 #define SRV_META_USER 0x03de
157 #define SRV_META_USER_SUBCMD 0x0000
158 #define SRV_META_USER_RESULT 0x0002
159 #define SRV_META_USER_DATA 0x0003
161 #define SRV_UPDATE_SUCCESS 0x01e0
163 #define SRV_UPDATE_FAIL 0x01ea
166 * ICQv5 SRV_META_USER subcommands
168 #define META_EX_USER_FOUND 0x0190
169 #define META_USER_FOUND 0x019a
170 #define META_ABOUT 0x00e6
171 #define META_USER_INFO 0x00c8
173 #define SRV_RECV_MESSAGE 0x00dc
174 #define SRV_RECV_MSG_UIN 0x0000
175 #define SRV_RECV_MSG_YEAR 0x0004
176 #define SRV_RECV_MSG_MONTH 0x0006
177 #define SRV_RECV_MSG_DAY 0x0007
178 #define SRV_RECV_MSG_HOUR 0x0008
179 #define SRV_RECV_MSG_MINUTE 0x0009
180 #define SRV_RECV_MSG_MSG_TYPE 0x000a
182 #define SRV_RAND_USER 0x024e
183 #define SRV_RAND_USER_UIN 0x0000
184 #define SRV_RAND_USER_IP 0x0004
185 #define SRV_RAND_USER_PORT 0x0008
186 #define SRV_RAND_USER_REAL_IP 0x000c
187 #define SRV_RAND_USER_CLASS 0x0010
188 #define SRV_RAND_USER_X1 0x0011
189 #define SRV_RAND_USER_STATUS 0x0015
190 #define SRV_RAND_USER_TCP_VER 0x0019
192 /* This message has the same structure as cmd_send_msg */
193 #define SRV_SYS_DELIVERED_MESS 0x0104
195 cmdcode serverMetaSubCmdCode[] = {
196 { "META_USER_FOUND", META_USER_FOUND },
197 { "META_EX_USER_FOUND", META_EX_USER_FOUND },
198 { "META_ABOUT", META_ABOUT },
199 { "META_USER_INFO", META_USER_INFO },
203 cmdcode serverCmdCode[] = {
204 { "SRV_ACK", SRV_ACK },
205 { "SRV_SILENT_TOO_LONG", SRV_SILENT_TOO_LONG },
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 },
218 { "SRV_END_OFFLINE_MESSAGES", 230 },
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 },
230 { "SRV_END_CONTACTLIST_STATUS", 540 },
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, NullTVB,
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, NullTVB,
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_icqv4(const u_char *pd,
562 /* Not really implemented yet */
563 if (check_col(fd, COL_PROTOCOL)) {
564 col_set_str(fd, COL_PROTOCOL, "ICQv4 (UDP)");
566 if (check_col(fd, COL_INFO)) {
567 col_set_str(fd, COL_INFO, "ICQ Version 4 protocol");
572 dissect_icqv3(const u_char *pd,
577 /* Not really implemented yet */
578 if (check_col(fd, COL_PROTOCOL)) {
579 col_set_str(fd, COL_PROTOCOL, "ICQv3 (UDP)");
581 if (check_col(fd, COL_INFO)) {
582 col_set_str(fd, COL_INFO, "ICQ Version 3 protocol");
587 dissect_icqv2(const u_char *pd,
592 /* Not really implemented yet */
593 if (check_col(fd, COL_PROTOCOL)) {
594 col_set_str(fd, COL_PROTOCOL, "ICQv2 (UDP)");
596 if (check_col(fd, COL_INFO)) {
597 col_set_str(fd, COL_INFO, "ICQ Version 2 protocol");
602 * Find first occurrence of ch in buf
603 * Buf is max size big.
606 strnchr(const u_char* buf, u_char ch, int size)
609 u_char* p = (u_char*) buf;
610 for (i=0;(*p) && (*p!=ch) && (i<size); p++, i++)
612 if ((*p == '\0') || (i>=size))
618 * The packet at pd has a (len, string) pair.
619 * Copy the string to a buffer, and display it in the tree.
620 * Observe any limits you might cross.
622 * If anything is wrong, return -1, since -1 is not a valid string
623 * length. Else, return the number of chars processed.
626 proto_add_icq_attr(proto_tree* tree, /* The tree to add to */
627 const char* pd, /* Pointer to the field */
628 const int offset, /* Offset from the start of packet */
629 const int size, /* The number of bytes left in pd */
630 char* descr) /* The description to use in the tree */
636 if (size<sizeof(guint16))
639 left -= sizeof(guint16);
641 proto_tree_add_text(tree, NullTVB,
648 data = g_malloc(len);
650 strncpy(data, pd + sizeof(guint16), len);
651 data[len - 1] = '\0';
653 proto_tree_add_text(tree, NullTVB,
655 sizeof(guint16) + len,
656 "%s[%u]: %s", descr, len, data);
659 return len + sizeof(guint16);
663 icqv5_decode_msgType(proto_tree* tree,
664 const unsigned char* pd, /* From start of messageType */
668 proto_item* ti = NULL;
669 proto_tree* subtree = NULL;
671 char *msgText = NULL;
672 guint16 msgType = -1;
675 static char* auth_req_field_descr[] = {
682 static char* emain_field_descr[] = {
691 enum {OFF_MSG_TYPE=0,
696 if (left >= sizeof(guint16)) {
697 msgType = pletohs(pd + OFF_MSG_TYPE);
698 left -= sizeof(guint16);
700 if (left >= sizeof(guint16)) {
701 msgLen = pletohs(pd + OFF_MSG_LEN);
702 left -= sizeof(guint16);
705 ti = proto_tree_add_text(tree, NullTVB,
708 "Type: %u (%s)", msgType, findMsgType(msgType));
709 /* Create a new subtree */
710 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
713 case 0xffff: /* Field unknown */
716 fprintf(stderr, "Unknown msgType: %u (%04x)\n", msgType, msgType);
719 msgText = g_malloc(left + 1);
720 strncpy(msgText, pd + OFF_MSG_TEXT, left);
721 msgText[left] = '\0';
722 proto_tree_add_text(subtree, NullTVB,
723 offset + OFF_MSG_TEXT,
729 /* Two parts, a description and the URL. Separeted by FE */
730 for (i=0;i<left;i++) {
731 if (pd[OFF_MSG_TEXT + i] == 0xfe)
734 msgText = g_malloc(i + 1);
735 strncpy(msgText, pd + OFF_MSG_TEXT, i);
740 proto_tree_add_text(subtree, NullTVB,
741 offset + OFF_MSG_TEXT,
743 "Description: %s", msgText);
746 msgText = g_realloc(msgText, left - i);
747 strncpy(msgText, pd + OFF_MSG_TEXT + i + 1, left - i - 1);
748 msgText[left - i] = '\0';
749 proto_tree_add_text(subtree, NullTVB,
750 offset + OFF_MSG_TEXT,
759 for (n = 0; n < 6; n++) {
761 (i<left) && (pd[OFF_MSG_TEXT+i]!=0xfe);
765 msgText = g_realloc(msgText, i-j);
766 strncpy(msgText, pd + OFF_MSG_TEXT + j, i - j - 1);
767 msgText[i-j-1] = '\0';
768 proto_tree_add_text(subtree, NullTVB,
769 offset + OFF_MSG_TEXT + j,
771 "%s: %s", emain_field_descr[n], msgText);
773 proto_tree_add_text(subtree, NullTVB,
774 offset + OFF_MSG_TEXT + j,
776 "%s: %s", emain_field_descr[n], "(empty)");
786 /* Three bytes, first is a char signifying success */
787 unsigned char auth_suc = pd[OFF_MSG_LEN];
788 guint16 x1 = pd[OFF_MSG_LEN+1];
789 proto_tree_add_text(subtree, NullTVB,
790 offset + OFF_MSG_LEN,
792 "Authorization: (%u) %s",auth_suc,
793 (auth_suc==0)?"Denied":"Allowed");
794 proto_tree_add_text(subtree, NullTVB,
795 offset + OFF_MSG_LEN + 1,
801 /* Six parts, separated by FE */
804 msgText = g_malloc(64);
805 for (n = 0; n < 6 && i<left; n++) {
806 while (i<left && pd[OFF_MSG_TEXT+i]!=0xfe)
809 /* pd[OFF_MSG_TEXT+i] == 0xfe */
811 /* Otherwise, it'd be a null string */
812 msgText = g_realloc(msgText, i - j);
813 strncpy(msgText, pd + OFF_MSG_TEXT + j, i-j);
815 proto_tree_add_text(subtree, NullTVB,
816 offset + OFF_MSG_TEXT + j,
818 "%s: %s", auth_req_field_descr[n], msgText);
820 proto_tree_add_text(subtree, NullTVB,
821 offset + OFF_MSG_TEXT + j,
823 "%s: %s", auth_req_field_descr[n], "(null)");
826 /* i and j point after the 0xfe character */
834 /* Four parts, separated by FE */
837 /* This is necessary, because g_realloc does not behave like
838 * g_malloc if the first parameter == NULL */
839 msgText = g_malloc(64);
840 for (n = 0; n < 4 && i<left; n++) {
841 while (i<left && pd[OFF_MSG_TEXT+i]!=0xfe)
844 /* pd[OFF_MSG_TEXT+i] == 0xfe */
846 /* Otherwise, it'd be a null string */
847 msgText = g_realloc(msgText, i - j);
848 strncpy(msgText, pd + OFF_MSG_TEXT + j, i-j);
850 proto_tree_add_text(subtree, NullTVB,
851 offset + OFF_MSG_TEXT + j,
853 "%s: %s", auth_req_field_descr[n], msgText);
855 proto_tree_add_text(subtree, NullTVB,
856 offset + OFF_MSG_TEXT + j,
858 "%s: %s", auth_req_field_descr[n], "(null)");
861 /* i and j point after the 0xfe character */
869 u_char* p = (u_char*) &pd[OFF_MSG_TEXT];
871 int sz = 0; /* Size of the current element */
872 int n = 0; /* The nth element */
873 int done = 0; /* Number of chars processed */
874 u_char* msgText2 = NULL;
876 /* Create a new subtree */
877 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
879 p = strnchr(pprev, 0xfe, left);
882 sz = (int)(p - pprev);
885 msgText = g_realloc(msgText, sz+1);
886 strncpy(msgText, pprev, sz);
890 /* The first element is the number of Nick/UIN pairs follow */
891 proto_tree_add_text(subtree, NullTVB,
892 offset + OFF_MSG_TEXT + done,
894 "Number of pairs: %s", msgText);
896 } else if (p!=NULL) {
900 p = strnchr(pprev, 0xfe, left);
902 sz = (int)(p - pprev);
905 msgText2 = g_malloc(sz+1);
906 strncpy(msgText2, pprev, sz);
909 proto_tree_add_text(subtree, NullTVB,
910 offset + OFF_MSG_TEXT + done,
912 "%s:%s", msgText, msgText2);
926 /*********************************
930 *********************************/
932 icqv5_cmd_ack(proto_tree* tree,/* Tree to put the data in */
933 const u_char* pd, /* Packet content */
934 int offset, /* Offset from the start of the packet to the content */
935 int size) /* Number of chars left to do */
937 guint32 random = pletohl(pd + CMD_ACK_RANDOM);
942 ti = proto_tree_add_uint_format(tree,
949 subtree = proto_item_add_subtree(ti, ett_icq_body);
950 proto_tree_add_text(subtree, NullTVB,
951 offset + CMD_ACK_RANDOM,
953 "Random: 0x%08x", random);
958 icqv5_cmd_rand_search(proto_tree* tree, /* Tree to put the data in */
959 const u_char* pd, /* Packet content */
960 int offset, /* Offset from the start of the packet to the content */
961 int size) /* Number of chars left to do */
963 guint16 group = pletohs(pd + CMD_RAND_SEARCH_GROUP);
967 static const char* groups[] = {
982 ti = proto_tree_add_uint_format(tree,
989 subtree = proto_item_add_subtree(ti, ett_icq_body);
990 if (group>0 && (group<=sizeof(groups)/sizeof(const char*)))
991 proto_tree_add_text(subtree, NullTVB,
992 offset + CMD_RAND_SEARCH_GROUP,
994 "Group: (%u) %s", group, groups[group-1]);
996 proto_tree_add_text(subtree, NullTVB,
997 offset + CMD_RAND_SEARCH_GROUP,
999 "Group: (%u)", group);
1004 icqv5_cmd_ack_messages(proto_tree* tree,/* Tree to put the data in */
1005 const u_char* pd, /* Packet content */
1006 int offset, /* Offset from the start of the packet to the content */
1007 int size) /* Number of chars left to do */
1009 guint32 random = pletohl(pd + CMD_ACK_MESSAGES_RANDOM);
1010 proto_tree* subtree;
1014 ti = proto_tree_add_uint_format(tree,
1021 subtree = proto_item_add_subtree(ti, ett_icq_body);
1022 proto_tree_add_text(subtree, NullTVB,
1023 offset + CMD_ACK_MESSAGES_RANDOM,
1025 "Random: 0x%08x", random);
1030 icqv5_cmd_keep_alive(proto_tree* tree,/* Tree to put the data in */
1031 const u_char* pd, /* Packet content */
1032 int offset, /* Offset from the start of the packet to the content */
1033 int size) /* Number of chars left to do */
1035 guint32 random = pletohl(pd + CMD_KEEP_ALIVE_RANDOM);
1036 proto_tree* subtree;
1040 ti = proto_tree_add_uint_format(tree,
1047 subtree = proto_item_add_subtree(ti, ett_icq_body);
1048 proto_tree_add_text(subtree, NullTVB,
1049 offset + CMD_KEEP_ALIVE_RANDOM,
1051 "Random: 0x%08x", random);
1056 icqv5_cmd_send_text_code(proto_tree* tree,/* Tree to put the data in */
1057 const u_char* pd, /* Packet content */
1058 int offset, /* Offset from the start of the packet to the content */
1059 int size) /* Number of chars left to do */
1061 proto_tree* subtree = NULL;
1062 proto_item* ti = NULL;
1066 int left = size; /* The amount of data left to analyse */
1069 ti = proto_tree_add_uint_format(tree,
1078 if (left<sizeof(guint16))
1080 len = pletohs(pd+CMD_SEND_TEXT_CODE_LEN);
1081 left -= sizeof(gint16);
1083 subtree = proto_item_add_subtree(ti, ett_icq_body);
1084 proto_tree_add_text(subtree, NullTVB,
1085 offset + CMD_SEND_TEXT_CODE_LEN,
1091 len = MIN(len, left);
1092 text = g_malloc(len+1);
1093 memcpy(text, pd + CMD_SEND_TEXT_CODE_TEXT, len);
1097 proto_tree_add_text(subtree, NullTVB,
1098 offset + CMD_SEND_TEXT_CODE_TEXT,
1105 if (left<sizeof(gint16))
1108 x1 = pletohs(pd + size - left);
1109 left -= sizeof(gint16);
1111 proto_tree_add_text(subtree, NullTVB,
1112 offset + CMD_SEND_TEXT_CODE_TEXT + len,
1119 icqv5_cmd_add_to_list(proto_tree* tree,/* Tree to put the data in */
1120 const u_char* pd, /* Packet content */
1121 int offset, /* Offset from the start of the packet to the content */
1122 int size) /* Number of chars left to do */
1125 proto_tree* subtree;
1128 uin = pletohl(pd + CMD_ADD_TO_LIST);
1130 ti = proto_tree_add_uint_format(tree,
1137 subtree = proto_item_add_subtree(ti, ett_icq_body);
1138 proto_tree_add_text(subtree, NullTVB,
1139 offset + CMD_ADD_TO_LIST_UIN,
1146 icqv5_cmd_status_change(proto_tree* tree,/* Tree to put the data in */
1147 const u_char* pd, /* Packet content */
1148 int offset, /* Offset from the start of the packet to the content */
1149 int size) /* Number of chars left to do */
1151 guint32 status = -1;
1152 proto_tree* subtree;
1155 if (size >= CMD_STATUS_CHANGE_STATUS + 4)
1156 status = pletohl(pd + CMD_STATUS_CHANGE_STATUS);
1158 ti = proto_tree_add_uint_format(tree,
1165 subtree = proto_item_add_subtree(ti, ett_icq_body);
1167 proto_tree_add_text(subtree, NullTVB,
1168 offset + CMD_STATUS_CHANGE_STATUS,
1170 "Status: %08x (%s)", status, findStatus(status));
1175 icqv5_cmd_send_msg(proto_tree* tree,
1181 proto_tree* subtree;
1183 guint32 receiverUIN = 0xffffffff;
1184 guint16 msgType = 0xffff;
1185 guint16 msgLen = 0xffff;
1186 int left = size; /* left chars to do */
1190 receiverUIN = pletohl(pd + CMD_SEND_MSG_RECV_UIN);
1194 msgType = pletohs(pd + CMD_SEND_MSG_MSG_TYPE);
1198 msgLen = pletohs(pd + CMD_SEND_MSG_MSG_LEN);
1202 ti = proto_tree_add_uint_format(tree,
1209 subtree = proto_item_add_subtree(ti, ett_icq_body);
1210 proto_tree_add_text(subtree, NullTVB,
1211 offset + CMD_SEND_MSG_RECV_UIN,
1213 "Receiver UIN: %u", receiverUIN);
1214 proto_tree_add_text(subtree, NullTVB,
1215 offset + CMD_SEND_MSG_MSG_LEN,
1217 "Length: %u", msgLen);
1219 icqv5_decode_msgType(subtree,
1220 pd + CMD_SEND_MSG_MSG_TYPE,
1221 offset + CMD_SEND_MSG_MSG_TYPE,
1222 left+4); /* There are 4 bytes more... */
1227 icqv5_cmd_login(proto_tree* tree,
1233 proto_tree* subtree;
1234 time_t theTime = -1;
1236 guint32 passwdLen = -1;
1237 char* password = NULL;
1238 const u_char *ipAddrp = NULL;
1239 guint32 status = -1;
1240 guint32 left = size;
1243 theTime = pletohl(pd + CMD_LOGIN_TIME);
1246 port = pletohl(pd + CMD_LOGIN_PORT);
1249 passwdLen = pletohs(pd + CMD_LOGIN_PASSLEN);
1251 if (left>=10+passwdLen) {
1252 password = g_malloc(passwdLen + 1);
1253 strncpy(password, pd + CMD_LOGIN_PASSWD, passwdLen);
1254 password[passwdLen] = '\0';
1257 if (left>=10+passwdLen+CMD_LOGIN_IP+4) {
1258 ipAddrp = pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP;
1260 if (left>=10+passwdLen+CMD_LOGIN_STATUS+4) {
1261 status = pletohs(pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS);
1264 ti = proto_tree_add_uint_format(tree,
1271 subtree = proto_item_add_subtree(ti, ett_icq_body);
1273 char *aTime = ctime(&theTime);
1275 aTime[strlen(aTime)-1] = '\0';
1276 proto_tree_add_text(subtree, NullTVB,
1277 offset + CMD_LOGIN_TIME,
1279 "Time: %ld = %s", (long)theTime, aTime);
1282 proto_tree_add_text(subtree, NullTVB,
1283 offset + CMD_LOGIN_PORT,
1286 if ((passwdLen!=-1) && (password!=NULL))
1287 proto_tree_add_text(subtree, NullTVB,
1288 offset + CMD_LOGIN_PASSLEN,
1290 "Passwd: %s", password);
1292 proto_tree_add_text(subtree, NullTVB,
1293 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP,
1295 "IP: %s", ip_to_str(ipAddrp));
1297 proto_tree_add_text(subtree, NullTVB,
1298 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS,
1300 "Status: %s", findStatus(status));
1307 icqv5_cmd_contact_list(proto_tree* tree,
1312 proto_tree* subtree;
1314 unsigned char num = -1;
1317 const u_char* p = NULL;
1319 if (size >= CMD_CONTACT_LIST_NUM + 1)
1320 num = pd[CMD_CONTACT_LIST_NUM];
1323 ti = proto_tree_add_uint_format(tree,
1330 subtree = proto_item_add_subtree(ti, ett_icq_body);
1331 proto_tree_add_text(subtree, NullTVB,
1332 offset + CMD_CONTACT_LIST,
1334 "Number of uins: %u", num);
1336 * A sequence of num times UIN follows
1338 offset += (CMD_CONTACT_LIST_NUM + 1);
1340 p = &pd[CMD_CONTACT_LIST_NUM + 1];
1341 for (i = 0; (i<num) && (left>0);i++) {
1344 proto_tree_add_text(subtree, NullTVB,
1347 "UIN[%d]: %u",i,uin);
1357 icqv5_cmd_no_params(proto_tree* tree,/* Tree to put the data in */
1358 const u_char* pd, /* Packet content */
1359 int offset, /* Offset from the start of the packet to the content */
1360 int size, /* Number of chars left to do */
1363 proto_tree* subtree;
1367 ti = proto_tree_add_uint_format(tree,
1374 subtree = proto_item_add_subtree(ti, ett_icq_body);
1375 proto_tree_add_text(subtree, NullTVB,
1382 /**********************
1386 **********************
1389 icqv5_srv_no_params(proto_tree* tree,/* Tree to put the data in */
1390 const u_char* pd, /* Packet content */
1391 int offset, /* Offset from the start of the packet to the content */
1392 int size, /* Number of chars left to do */
1395 proto_tree* subtree;
1399 ti = proto_tree_add_uint_format(tree,
1406 subtree = proto_item_add_subtree(ti, ett_icq_body);
1407 proto_tree_add_text(subtree, NullTVB,
1415 icqv5_srv_login_reply(proto_tree* tree,/* Tree to put the data in */
1416 const u_char* pd, /* Packet content */
1417 int offset, /* Offset from the start of the packet to the content */
1418 int size) /* Number of chars left to do */
1420 proto_tree* subtree;
1422 const u_char *ipAddrp = NULL;
1424 if (size >= SRV_LOGIN_REPLY_IP + 4)
1425 ipAddrp = &pd[SRV_LOGIN_REPLY_IP];
1428 ti = proto_tree_add_uint_format(tree,
1432 SRV_LOGIN_REPLY_IP + 8,
1435 subtree = proto_item_add_subtree(ti, ett_icq_body);
1436 proto_tree_add_text(subtree, NullTVB,
1437 offset + SRV_LOGIN_REPLY_IP,
1439 "IP: %s", ip_to_str(ipAddrp));
1444 icqv5_srv_user_online(proto_tree* tree,/* Tree to put the data in */
1445 const u_char* pd, /* Packet content */
1446 int offset, /* Offset from the start of the packet to the content */
1447 int size) /* Number of chars left to do */
1449 proto_tree* subtree;
1452 const u_char *ipAddrp = NULL;
1454 const u_char *realipAddrp = NULL;
1455 guint32 status = -1;
1456 guint32 version = -1;
1458 if (size >= SRV_USER_ONL_UIN + 4)
1459 uin = pletohl(pd + SRV_USER_ONL_UIN);
1461 if (size >= SRV_USER_ONL_IP + 4)
1462 ipAddrp = &pd[SRV_USER_ONL_IP];
1464 if (size >= SRV_USER_ONL_PORT + 4)
1465 port = pletohl(pd + SRV_USER_ONL_PORT);
1467 if (size >= SRV_USER_ONL_REALIP + 4)
1468 realipAddrp = &pd[SRV_USER_ONL_REALIP];
1470 if (size >= SRV_USER_ONL_STATUS + 2)
1471 status = pletohs(pd + SRV_USER_ONL_STATUS);
1474 * Kojak: Hypothesis is that this field might be an encoding for the
1475 * version used by the UIN that changed. To test this, I included
1476 * this line to the code.
1478 if (size >= SRV_USER_ONL_X2 + 4)
1479 version = pletohl(pd + SRV_USER_ONL_X2);
1482 ti = proto_tree_add_uint_format(tree,
1486 SRV_LOGIN_REPLY_IP + 8,
1489 subtree = proto_item_add_subtree(ti, ett_icq_body);
1490 proto_tree_add_text(subtree, NullTVB,
1491 offset + SRV_USER_ONL_UIN,
1494 proto_tree_add_text(subtree, NullTVB,
1495 offset + SRV_USER_ONL_IP,
1497 "IP: %s", ip_to_str(ipAddrp));
1498 proto_tree_add_text(subtree, NullTVB,
1499 offset + SRV_USER_ONL_PORT,
1502 proto_tree_add_text(subtree, NullTVB,
1503 offset + SRV_USER_ONL_REALIP,
1505 "RealIP: %s", ip_to_str(realipAddrp));
1506 proto_tree_add_text(subtree, NullTVB,
1507 offset + SRV_USER_ONL_STATUS,
1509 "Status: %s", findStatus(status));
1510 proto_tree_add_text(subtree, NullTVB,
1511 offset + SRV_USER_ONL_X2,
1513 "Version: %08x", version);
1518 icqv5_srv_user_offline(proto_tree* tree,/* Tree to put the data in */
1519 const u_char* pd, /* Packet content */
1520 int offset, /* Offset from the start of the packet to the content */
1521 int size) /* Number of chars left to do */
1523 proto_tree* subtree;
1527 if (size >= SRV_USER_OFFLINE + 4)
1528 uin = pletohl(&pd[SRV_USER_OFFLINE]);
1531 ti = proto_tree_add_uint_format(tree,
1535 SRV_USER_OFFLINE_UIN + 4,
1538 subtree = proto_item_add_subtree(ti, ett_icq_body);
1539 proto_tree_add_text(subtree, NullTVB,
1540 offset + SRV_USER_OFFLINE_UIN,
1547 icqv5_srv_multi(proto_tree* tree,/* Tree to put the data in */
1548 const u_char* pd, /* Packet content */
1549 int offset, /* Offset from the start of the packet to the content */
1550 int size, /* Number of chars left to do */
1553 proto_tree* subtree;
1555 unsigned char num = -1;
1558 const u_char* p = NULL;
1560 if (size >= SRV_MULTI_NUM + 1)
1561 num = pd[SRV_MULTI_NUM];
1564 ti = proto_tree_add_uint_format(tree,
1571 subtree = proto_item_add_subtree(ti, ett_icq_body);
1572 proto_tree_add_text(subtree, NullTVB,
1573 offset + SRV_MULTI_NUM,
1575 "Number of pkts: %u", num);
1577 * A sequence of num times ( pktsize, packetData) follows
1579 offset += (SRV_MULTI_NUM + 1);
1581 p = &pd[SRV_MULTI_NUM + 1];
1582 for (i = 0; (i<num) && (left>0);i++) {
1589 dissect_icqv5Server(p, offset, fd, subtree, pktSz);
1600 icqv5_srv_meta_user(proto_tree* tree, /* Tree to put the data in */
1601 const u_char* pd, /* Packet content */
1602 int offset, /* Offset from the start of the packet to the content */
1603 int size) /* Number of chars left to do */
1606 proto_tree* subtree = NULL;
1608 proto_tree* sstree = NULL;
1609 proto_item* ti = NULL;
1613 guint16 subcmd = -1;
1614 unsigned char result = -1;
1616 if (size>=SRV_META_USER_SUBCMD + 2)
1617 subcmd = pletohs(pd+SRV_META_USER_SUBCMD);
1618 if (size>=SRV_META_USER_RESULT + 1)
1619 result = pd[SRV_META_USER_RESULT];
1623 ti = proto_tree_add_uint_format(tree,
1630 subtree = proto_item_add_subtree(ti, ett_icq_body);
1631 ti = proto_tree_add_text(subtree, NullTVB,
1632 offset + SRV_META_USER_SUBCMD,
1634 "%s", findSubCmd(subcmd));
1635 proto_tree_add_text(subtree, NullTVB,
1636 offset + SRV_META_USER_RESULT,
1638 "%s", (result==0x0a)?"Success":"Failure");
1639 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1641 ti = proto_tree_add_text(tree, NullTVB,
1642 offset + SRV_META_USER_SUBCMD,
1644 "%s", findSubCmd(subcmd));
1645 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1646 proto_tree_add_text(sstree, NullTVB,
1647 offset + SRV_META_USER_RESULT,
1649 "%s", (result==0x0a)?"Success":"Failure");
1652 /* Skip the META_USER header */
1657 case META_EX_USER_FOUND:
1659 /* This is almost the same as META_USER_FOUND,
1660 * however, there's an extra length field
1662 guint16 pktLen = -1;
1664 /* Read the lenght field */
1665 pktLen = pletohs(p);
1666 proto_tree_add_text(sstree, NullTVB,
1667 offset + size - left,
1669 "Length: %u", pktLen);
1671 p += sizeof(guint16); left -= sizeof(guint16);
1673 case META_USER_FOUND:
1675 /* The goto mentioned in this block should be local to this
1676 * block if C'd allow it.
1678 * They are used to "implement" a poorman's exception handling
1695 if (left<sizeof(guint32))
1698 proto_tree_add_text(sstree, NullTVB,
1699 offset + size - left,
1702 p+=sizeof(guint32);left-=sizeof(guint32);
1704 for ( ; *d!=NULL; d++) {
1705 len = proto_add_icq_attr(sstree,
1707 offset + size - left,
1712 p += len; left -= len;
1714 /* Get the authorize setting */
1715 if (left<sizeof(unsigned char))
1718 proto_tree_add_text(sstree, NullTVB,
1719 offset + size - left,
1721 "authorization: %s", (auth==0x01)?"Neccessary":"Who needs it");
1724 if (left<sizeof(guint16))
1727 proto_tree_add_text(sstree, NullTVB,
1728 offset + size - left,
1731 p+=sizeof(guint16);left-=sizeof(guint16);
1733 if (left<sizeof(guint32))
1736 proto_tree_add_text(sstree, NullTVB,
1737 offset + size - left,
1740 p+=sizeof(guint32);left-=sizeof(guint32);
1747 /* Get the about information */
1748 if (left<sizeof(guint16))
1751 p+=sizeof(guint16);left-=sizeof(guint16);
1752 if ((len<=0) || (left<len))
1754 about = g_malloc(len);
1755 strncpy(about, p, len);
1756 proto_tree_add_text(sstree, NullTVB,
1757 offset + size - left,
1758 sizeof(guint16)+len,
1759 "About(%d): %s", len, about);
1765 case META_USER_INFO:
1767 /* The goto mentioned in this block should be local to this
1768 * block if C'd allow it.
1770 * They are used to "implement" a poorman's exception handling
1772 static const char* descr[] = {
1787 const char** d = descr;
1790 unsigned char user_timezone = -1;
1791 unsigned char auth = -1;
1795 if (left<sizeof(guint32))
1798 proto_tree_add_text(sstree, NullTVB,
1799 offset + size - left,
1802 p+=sizeof(guint32);left-=sizeof(guint32);
1806 * Get every field from the description
1808 while ((*d)!=NULL) {
1809 if (left<sizeof(guint16))
1812 p+=sizeof(guint16);left-=sizeof(guint16);
1813 if ((len<0) || (left<len))
1816 item = g_malloc(len);
1817 strncpy(item, p, len);
1818 proto_tree_add_text(sstree, NullTVB,
1819 offset + size - left - sizeof(guint16),
1820 sizeof(guint16)+len,
1821 "%s(%d): %s",*d, len, item);
1827 /* Get country code */
1828 if (left<sizeof(guint16))
1830 country = pletohs(p);
1831 proto_tree_add_text(sstree, NullTVB,
1832 offset + size - left,
1834 "Countrycode: %u", country);
1835 p+=sizeof(guint16); left-=sizeof(guint16);
1836 /* Get the timezone setting */
1837 if (left<sizeof(unsigned char))
1840 proto_tree_add_text(sstree, NullTVB,
1841 offset + size - left,
1842 sizeof(unsigned char),
1843 "Timezone: %u", user_timezone);
1845 /* Get the authorize setting */
1846 if (left<sizeof(unsigned char))
1849 proto_tree_add_text(sstree, NullTVB,
1850 offset + size - left,
1851 sizeof(unsigned char),
1852 "Authorization: (%u) %s",
1853 auth, (auth==0)?"No":"Yes");
1855 /* Get the webaware setting */
1856 if (left<sizeof(unsigned char))
1859 proto_tree_add_text(sstree, NullTVB,
1860 offset + size - left,
1861 sizeof(unsigned char),
1862 "Webaware: (%u) %s",
1863 auth, (auth==0)?"No":"Yes");
1865 /* Get the authorize setting */
1866 if (left<sizeof(unsigned char))
1869 proto_tree_add_text(sstree, NullTVB,
1870 offset + size - left,
1871 sizeof(unsigned char),
1873 auth, (auth==0)?"No":"Yes");
1878 /* This information is already printed in the tree */
1879 fprintf(stderr, "Meta subcmd: %04x\n", subcmd);
1886 icqv5_srv_recv_message(proto_tree* tree, /* Tree to put the data in */
1887 const u_char* pd, /* Packet content */
1888 int offset, /* Offset from the start of the packet to the content */
1889 int size) /* Number of chars left to do */
1891 proto_tree* subtree = NULL;
1892 proto_item* ti = NULL;
1896 unsigned char month = -1;
1897 unsigned char day = -1;
1898 unsigned char hour = -1;
1899 unsigned char minute = -1;
1902 ti = proto_tree_add_uint_format(tree,
1909 subtree = proto_item_add_subtree(ti, ett_icq_body);
1910 if (left>=sizeof(guint32)) {
1911 uin = pletohl(pd + SRV_RECV_MSG_UIN);
1912 proto_tree_add_uint_format(subtree,
1915 offset + SRV_RECV_MSG_UIN,
1919 left -= sizeof(guint32);
1922 if (left>=(sizeof(guint16)+4*sizeof(unsigned char))) {
1923 year = pletohs(pd + SRV_RECV_MSG_YEAR);
1924 month = pd[SRV_RECV_MSG_MONTH];
1925 day = pd[SRV_RECV_MSG_DAY];
1926 hour = pd[SRV_RECV_MSG_HOUR];
1927 minute = pd[SRV_RECV_MSG_MINUTE];
1929 proto_tree_add_text(subtree, NullTVB,
1930 offset + SRV_RECV_MSG_YEAR,
1931 sizeof(guint16) + 4*sizeof(unsigned char),
1932 "Time: %u-%u-%u %02u:%02u",
1933 day, month, year, hour, minute);
1935 left -= (sizeof(guint16)+4*sizeof(unsigned char));
1938 icqv5_decode_msgType(subtree,
1939 pd + SRV_RECV_MSG_MSG_TYPE,
1940 offset + SRV_RECV_MSG_MSG_TYPE,
1946 icqv5_srv_rand_user(proto_tree* tree, /* Tree to put the data in */
1947 const u_char* pd, /* Packet content */
1948 int offset, /* Offset from the start of the packet to the content */
1949 int size) /* Number of chars left to do */
1951 proto_tree* subtree = NULL;
1952 proto_item* ti = NULL;
1954 const unsigned char* IP = NULL;
1956 const unsigned char* realIP = NULL;
1957 unsigned char commClass = -1;
1963 ti = proto_tree_add_uint_format(tree,
1967 SRV_RAND_USER_TCP_VER + 2,
1970 subtree = proto_item_add_subtree(ti, ett_icq_body);
1972 if (left<sizeof(guint32))
1974 uin = pletohl(pd + SRV_RAND_USER_UIN);
1975 proto_tree_add_text(subtree, NullTVB,
1976 offset + SRV_RAND_USER_UIN,
1979 left -= sizeof(guint32);
1981 if (left<sizeof(guint32))
1983 IP = pd + SRV_RAND_USER_IP;
1984 proto_tree_add_text(subtree, NullTVB,
1985 offset + SRV_RAND_USER_IP,
1987 "IP: %s", ip_to_str(IP));
1988 left -= sizeof(guint32);
1989 /* guint32 portNum */
1990 if (left<sizeof(guint32))
1992 port = pletohs(pd + SRV_RAND_USER_PORT);
1993 proto_tree_add_text(subtree, NullTVB,
1994 offset + SRV_RAND_USER_UIN,
1997 left -= sizeof(guint32);
1998 /* guint32 realIP */
1999 if (left<sizeof(guint32))
2001 realIP = pd + SRV_RAND_USER_REAL_IP;
2002 proto_tree_add_text(subtree, NullTVB,
2003 offset + SRV_RAND_USER_REAL_IP,
2005 "RealIP: %s", ip_to_str(realIP));
2006 left -= sizeof(guint32);
2007 /* guit16 Communication Class */
2008 if (left<sizeof(unsigned char))
2010 commClass = pd[SRV_RAND_USER_CLASS];
2011 proto_tree_add_text(subtree, NullTVB,
2012 offset + SRV_RAND_USER_CLASS,
2013 sizeof(unsigned char),
2014 "Class: %s", (commClass!=4)?"User to User":"Through Server");
2015 left -= sizeof(unsigned char);
2016 /* guint32 status */
2017 if (left<sizeof(guint32))
2019 status = pletohs(pd + SRV_RAND_USER_STATUS);
2020 proto_tree_add_text(subtree, NullTVB,
2021 offset + SRV_RAND_USER_STATUS,
2023 "Status: (%u) %s", status, findStatus(status));
2024 /* guint16 tcpVersion */
2025 if (left<sizeof(guint16))
2027 tcpVer = pletohs(pd + SRV_RAND_USER_TCP_VER);
2028 proto_tree_add_text(subtree, NullTVB,
2029 offset + SRV_RAND_USER_TCP_VER,
2031 "TCPVersion: %u", tcpVer);
2032 left -= sizeof(guint16);
2037 * Dissect all the v5 client traffic. This is encrypted, so be careful.
2040 dissect_icqv5Client(const u_char *pd,
2045 proto_tree *icq_tree = NULL;
2046 proto_tree *icq_header_tree = NULL;
2047 proto_tree *icq_decode_tree = NULL;
2048 proto_item *ti = NULL;
2050 guint16 version = -1, cmd = -1;
2051 guint16 seqnum1 = 0 , seqnum2 = 0;
2052 guint32 uin = -1, sessionid = -1;
2054 guint16 pktsize = -1; /* The size of the ICQ content */
2055 static u_char *decr_pd = NULL; /* Decrypted content */
2056 static int decr_size = 0; /* Size of decrypted-content buffer */
2058 pktsize = END_OF_FRAME;
2060 if (decr_size == 0 ) {
2061 decr_size = sizeof(u_char) * 128;
2062 decr_pd = g_malloc(decr_size);
2065 while (decr_size < pktsize + 3) {
2067 decr_pd = g_realloc(decr_pd, decr_size);
2070 /* First copy the memory, we don't want to overwrite the old content */
2071 memcpy(decr_pd, &pd[offset], pktsize);
2073 key = get_v5key(decr_pd, pktsize);
2074 decrypt_v5(decr_pd, pktsize, key);
2076 /* This information only makes sense in the decrypted version */
2077 uin = pletohl(&decr_pd[ICQ5_CL_UIN]);
2078 cmd = pletohs(&decr_pd[ICQ5_CL_CMD]);
2079 sessionid = pletohl(&decr_pd[ICQ5_CL_SESSIONID]);
2080 version = pletohs(&decr_pd[ICQ_VERSION]);
2081 seqnum1 = pletohs(&decr_pd[ICQ5_CL_SEQNUM1]);
2082 seqnum2 = pletohs(&decr_pd[ICQ5_CL_SEQNUM2]);
2084 if (check_col(fd, COL_INFO))
2085 col_add_fstr(fd, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
2089 ti = proto_tree_add_protocol_format(tree,
2094 "ICQv5 %s (len %u)",
2097 icq_tree = proto_item_add_subtree(ti, ett_icq);
2098 ti = proto_tree_add_uint_format(icq_tree,
2105 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
2107 proto_tree_add_text(icq_header_tree, NullTVB,
2108 offset + ICQ_VERSION,
2110 "Version: %u", version);
2111 proto_tree_add_uint_format(icq_header_tree,
2119 proto_tree_add_uint_format(icq_header_tree,
2122 offset+ICQ5_CL_SESSIONID,
2125 "Session ID: 0x%08x",
2127 proto_tree_add_text(icq_header_tree, NullTVB,
2128 offset + ICQ5_CL_CMD,
2130 "Command: %s (%u)", findClientCmd(cmd), cmd);
2131 proto_tree_add_text(icq_header_tree, NullTVB,
2132 offset + ICQ5_CL_SEQNUM1,
2134 "Seq Number 1: 0x%04x", seqnum1);
2135 proto_tree_add_text(icq_header_tree, NullTVB,
2136 offset + ICQ5_CL_SEQNUM2,
2138 "Seq Number 2: 0x%04x", seqnum2);
2139 proto_tree_add_uint_format(icq_header_tree,
2142 offset+ICQ5_CL_CHECKCODE,
2149 icqv5_cmd_ack(icq_tree,
2150 decr_pd + ICQ5_CL_HDRSIZE,
2151 offset + ICQ5_CL_HDRSIZE,
2152 pktsize - ICQ5_CL_HDRSIZE);
2155 case CMD_MSG_TO_NEW_USER:
2156 icqv5_cmd_send_msg(icq_tree,
2157 decr_pd + ICQ5_CL_HDRSIZE,
2158 offset + ICQ5_CL_HDRSIZE,
2159 pktsize - ICQ5_CL_HDRSIZE,
2162 case CMD_RAND_SEARCH:
2163 icqv5_cmd_rand_search(icq_tree,
2164 decr_pd + ICQ5_CL_HDRSIZE,
2165 offset + ICQ5_CL_HDRSIZE,
2166 pktsize - ICQ5_CL_HDRSIZE);
2169 icqv5_cmd_login(icq_tree,
2170 decr_pd + ICQ5_CL_HDRSIZE,
2171 offset + ICQ5_CL_HDRSIZE,
2172 pktsize - ICQ5_CL_HDRSIZE);
2174 case CMD_SEND_TEXT_CODE:
2175 icqv5_cmd_send_text_code(icq_tree,
2176 decr_pd + ICQ5_CL_HDRSIZE,
2177 offset + ICQ5_CL_HDRSIZE,
2178 pktsize - ICQ5_CL_HDRSIZE);
2180 case CMD_STATUS_CHANGE:
2181 icqv5_cmd_status_change(icq_tree,
2182 decr_pd + ICQ5_CL_HDRSIZE,
2183 offset + ICQ5_CL_HDRSIZE,
2184 pktsize - ICQ5_CL_HDRSIZE);
2186 case CMD_ACK_MESSAGES:
2187 icqv5_cmd_ack_messages(icq_tree,
2188 decr_pd + ICQ5_CL_HDRSIZE,
2189 offset + ICQ5_CL_HDRSIZE,
2190 pktsize - ICQ5_CL_HDRSIZE);
2192 case CMD_KEEP_ALIVE:
2193 icqv5_cmd_keep_alive(icq_tree,
2194 decr_pd + ICQ5_CL_HDRSIZE,
2195 offset + ICQ5_CL_HDRSIZE,
2196 pktsize - ICQ5_CL_HDRSIZE);
2198 case CMD_ADD_TO_LIST:
2199 icqv5_cmd_add_to_list(icq_tree,
2200 decr_pd + ICQ5_CL_HDRSIZE,
2201 offset + ICQ5_CL_HDRSIZE,
2202 pktsize - ICQ5_CL_HDRSIZE);
2204 case CMD_CONTACT_LIST:
2205 icqv5_cmd_contact_list(icq_tree,
2206 decr_pd + ICQ5_CL_HDRSIZE,
2207 offset + ICQ5_CL_HDRSIZE,
2208 pktsize - ICQ5_CL_HDRSIZE);
2211 case CMD_REG_NEW_USER:
2212 case CMD_QUERY_SERVERS:
2213 case CMD_QUERY_ADDONS:
2214 icqv5_cmd_no_params(icq_tree,
2215 decr_pd + ICQ5_CL_HDRSIZE,
2216 offset + ICQ5_CL_HDRSIZE,
2217 pktsize - ICQ5_CL_HDRSIZE,
2221 proto_tree_add_uint_format(icq_tree,
2228 cmd, findClientCmd(cmd));
2229 fprintf(stderr,"Missing: %s\n", findClientCmd(cmd));
2232 ti = proto_tree_add_text(icq_tree, NullTVB,
2236 icq_decode_tree = proto_item_add_subtree(ti,
2238 proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
2244 dissect_icqv5Server(const u_char *pd,
2250 /* Server traffic is easy, not encrypted */
2251 proto_tree *icq_tree = NULL;
2252 proto_tree *icq_header_tree = NULL;
2253 proto_item *ti = NULL;
2254 const u_char* decr_pd;
2255 int changeCol = (pktsize==(guint32)-1);
2257 guint16 version, cmd;
2258 guint32 uin, sessionid;
2259 guint16 seqnum1, seqnum2;
2262 uin = pletohl(&pd[ICQ5_SRV_UIN]);
2263 sessionid = pletohl(&pd[ICQ5_SRV_SESSIONID]);
2264 cmd = pletohs(&pd[ICQ5_SRV_CMD]);
2265 version = pletohs(&pd[ICQ_VERSION]);
2266 checkcode = pletohl(&pd[ICQ5_SRV_CHECKCODE]);
2267 seqnum1 = pletohs(&pd[ICQ5_SRV_SEQNUM1]);
2268 seqnum2 = pletohs(&pd[ICQ5_SRV_SEQNUM2]);
2270 pktsize = END_OF_FRAME;
2273 if (changeCol && check_col(fd, COL_INFO))
2274 col_add_fstr(fd, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
2277 ti = proto_tree_add_protocol_format(tree,
2282 "ICQv5 %s (len %u)",
2286 icq_tree = proto_item_add_subtree(ti, ett_icq);
2288 ti = proto_tree_add_uint_format(icq_tree,
2295 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
2297 proto_tree_add_text(icq_header_tree, NullTVB,
2298 offset + ICQ_VERSION,
2300 "Version: %u", version);
2301 proto_tree_add_uint_format(icq_header_tree,
2304 offset+ICQ5_SRV_SESSIONID,
2307 "Session ID: 0x%08x",
2309 proto_tree_add_text(icq_header_tree, NullTVB,
2310 offset + ICQ5_SRV_CMD,
2312 "Command: %s (%u)", findServerCmd(cmd), cmd);
2313 proto_tree_add_text(icq_header_tree, NullTVB,
2314 offset + ICQ5_SRV_SEQNUM1,
2316 "Seq Number 1: 0x%04x", seqnum1);
2317 proto_tree_add_text(icq_header_tree, NullTVB,
2318 offset + ICQ5_SRV_SEQNUM2,
2320 "Seq Number 2: 0x%04x", seqnum2);
2321 proto_tree_add_uint_format(icq_header_tree,
2324 offset+ICQ5_SRV_UIN,
2329 proto_tree_add_uint_format(icq_header_tree,
2332 offset+ICQ5_SRV_CHECKCODE,
2335 "Checkcode: 0x%08x",
2339 icqv5_srv_rand_user(icq_tree,
2340 decr_pd + ICQ5_SRV_HDRSIZE,
2341 offset + ICQ5_SRV_HDRSIZE,
2342 pktsize - ICQ5_SRV_HDRSIZE);
2344 case SRV_SYS_DELIVERED_MESS:
2345 /* The message structures are all the same. Why not run
2346 * the same routine? */
2347 icqv5_cmd_send_msg(icq_tree,
2348 decr_pd + ICQ5_SRV_HDRSIZE,
2349 offset + ICQ5_SRV_HDRSIZE,
2350 pktsize - ICQ5_SRV_HDRSIZE,
2353 case SRV_USER_ONLINE:
2354 icqv5_srv_user_online(icq_tree,
2355 decr_pd + ICQ5_SRV_HDRSIZE,
2356 offset + ICQ5_SRV_HDRSIZE,
2357 pktsize - ICQ5_SRV_HDRSIZE);
2359 case SRV_USER_OFFLINE:
2360 icqv5_srv_user_offline(icq_tree,
2361 decr_pd + ICQ5_SRV_HDRSIZE,
2362 offset + ICQ5_SRV_HDRSIZE,
2363 pktsize - ICQ5_SRV_HDRSIZE);
2365 case SRV_LOGIN_REPLY:
2366 icqv5_srv_login_reply(icq_tree,
2367 decr_pd + ICQ5_SRV_HDRSIZE,
2368 offset + ICQ5_SRV_HDRSIZE,
2369 pktsize - ICQ5_SRV_HDRSIZE);
2372 icqv5_srv_meta_user(icq_tree,
2373 decr_pd + ICQ5_SRV_HDRSIZE,
2374 offset + ICQ5_SRV_HDRSIZE,
2375 pktsize - ICQ5_SRV_HDRSIZE);
2377 case SRV_RECV_MESSAGE:
2378 icqv5_srv_recv_message(icq_tree,
2379 decr_pd + ICQ5_SRV_HDRSIZE,
2380 offset + ICQ5_SRV_HDRSIZE,
2381 pktsize - ICQ5_SRV_HDRSIZE);
2384 icqv5_srv_multi(icq_tree,
2385 decr_pd + ICQ5_SRV_HDRSIZE,
2386 offset + ICQ5_SRV_HDRSIZE,
2387 pktsize - ICQ5_SRV_HDRSIZE,
2391 case SRV_SILENT_TOO_LONG:
2395 case SRV_UPDATE_SUCCESS:
2396 icqv5_srv_no_params(icq_tree,
2397 decr_pd + ICQ5_SRV_HDRSIZE,
2398 offset + ICQ5_SRV_HDRSIZE,
2399 pktsize - ICQ5_SRV_HDRSIZE,
2403 proto_tree_add_uint_format(icq_tree,
2406 offset + ICQ5_SRV_CMD,
2410 cmd, findServerCmd(cmd));
2411 fprintf(stderr,"Missing: %s\n", findServerCmd(cmd));
2417 static void dissect_icqv5(const u_char *pd,
2422 guint32 unknown = pletohl(&pd[offset + ICQ5_UNKNOWN]);
2424 if (check_col(fd, COL_PROTOCOL))
2425 col_set_str(fd, COL_PROTOCOL, "ICQv5 (UDP)");
2426 if (check_col(fd, COL_INFO))
2427 col_set_str(fd, COL_INFO, "ICQv5 packet");
2428 if (unknown == 0x0L) {
2429 dissect_icqv5Client(pd, offset, fd, tree);
2431 dissect_icqv5Server(pd + offset, offset, fd, tree, (guint32) -1);
2435 static void dissect_icq(const u_char *pd,
2442 OLD_CHECK_DISPLAY_AS_DATA(proto_icq, pd, offset, fd, tree);
2444 version = pletohs(&pd[offset + ICQ_VERSION]);
2447 dissect_icqv5(pd, offset, fd, tree);
2450 dissect_icqv4(pd, offset, fd, tree);
2453 dissect_icqv3(pd, offset, fd, tree);
2456 dissect_icqv2(pd, offset, fd, tree);
2459 fprintf(stderr, "ICQ: Unknown version (%d)\n", version);
2464 /* registration with the filtering engine */
2466 proto_register_icq(void)
2468 static hf_register_info hf[] = {
2470 {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2472 {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, ""}},
2473 { &hf_icq_sessionid,
2474 {"SessionID", "icq.sessionid", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2476 {"Command", "icq.cmd", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2477 { &hf_icq_checkcode,
2478 {"Checkcode", "icq.checkcode", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2480 {"Decode", "icq.decode", FT_STRING, BASE_NONE, NULL, 0x0, ""}}
2482 static gint *ett[] = {
2487 &ett_icq_body_parts,
2490 proto_icq = proto_register_protocol("ICQ Protocol", "ICQ", "icq");
2492 proto_register_field_array(proto_icq, hf, array_length(hf));
2494 proto_register_subtree_array(ett, array_length(ett));
2498 proto_reg_handoff_icq(void)
2500 old_dissector_add("udp.port", UDP_PORT_ICQ, dissect_icq);