2 * Routines for ICQ packet disassembly
4 * $Id: packet-icq.c,v 1.23 2000/11/19 19:23:54 gerald 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 */
2057 pktsize = END_OF_FRAME;
2059 if (decr_pd == NULL)
2060 decr_pd = (u_char *) g_malloc(sizeof (u_char) * 128);
2062 while (sizeof(decr_pd) < pktsize + 3)
2063 decr_pd = (u_char *) g_realloc(decr_pd, sizeof (decr_pd) * 2);
2065 /* First copy the memory, we don't want to overwrite the old content */
2066 memcpy(decr_pd, &pd[offset], pktsize);
2068 key = get_v5key(decr_pd, pktsize);
2069 decrypt_v5(decr_pd, pktsize, key);
2071 /* This information only makes sense in the decrypted version */
2072 uin = pletohl(&decr_pd[ICQ5_CL_UIN]);
2073 cmd = pletohs(&decr_pd[ICQ5_CL_CMD]);
2074 sessionid = pletohl(&decr_pd[ICQ5_CL_SESSIONID]);
2075 version = pletohs(&decr_pd[ICQ_VERSION]);
2076 seqnum1 = pletohs(&decr_pd[ICQ5_CL_SEQNUM1]);
2077 seqnum2 = pletohs(&decr_pd[ICQ5_CL_SEQNUM2]);
2079 if (check_col(fd, COL_INFO))
2080 col_add_fstr(fd, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
2084 ti = proto_tree_add_protocol_format(tree,
2089 "ICQv5 %s (len %u)",
2092 icq_tree = proto_item_add_subtree(ti, ett_icq);
2093 ti = proto_tree_add_uint_format(icq_tree,
2100 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
2102 proto_tree_add_text(icq_header_tree, NullTVB,
2103 offset + ICQ_VERSION,
2105 "Version: %u", version);
2106 proto_tree_add_uint_format(icq_header_tree,
2114 proto_tree_add_uint_format(icq_header_tree,
2117 offset+ICQ5_CL_SESSIONID,
2120 "Session ID: 0x%08x",
2122 proto_tree_add_text(icq_header_tree, NullTVB,
2123 offset + ICQ5_CL_CMD,
2125 "Command: %s (%u)", findClientCmd(cmd), cmd);
2126 proto_tree_add_text(icq_header_tree, NullTVB,
2127 offset + ICQ5_CL_SEQNUM1,
2129 "Seq Number 1: 0x%04x", seqnum1);
2130 proto_tree_add_text(icq_header_tree, NullTVB,
2131 offset + ICQ5_CL_SEQNUM2,
2133 "Seq Number 2: 0x%04x", seqnum2);
2134 proto_tree_add_uint_format(icq_header_tree,
2137 offset+ICQ5_CL_CHECKCODE,
2144 icqv5_cmd_ack(icq_tree,
2145 decr_pd + ICQ5_CL_HDRSIZE,
2146 offset + ICQ5_CL_HDRSIZE,
2147 pktsize - ICQ5_CL_HDRSIZE);
2150 case CMD_MSG_TO_NEW_USER:
2151 icqv5_cmd_send_msg(icq_tree,
2152 decr_pd + ICQ5_CL_HDRSIZE,
2153 offset + ICQ5_CL_HDRSIZE,
2154 pktsize - ICQ5_CL_HDRSIZE,
2157 case CMD_RAND_SEARCH:
2158 icqv5_cmd_rand_search(icq_tree,
2159 decr_pd + ICQ5_CL_HDRSIZE,
2160 offset + ICQ5_CL_HDRSIZE,
2161 pktsize - ICQ5_CL_HDRSIZE);
2164 icqv5_cmd_login(icq_tree,
2165 decr_pd + ICQ5_CL_HDRSIZE,
2166 offset + ICQ5_CL_HDRSIZE,
2167 pktsize - ICQ5_CL_HDRSIZE);
2169 case CMD_SEND_TEXT_CODE:
2170 icqv5_cmd_send_text_code(icq_tree,
2171 decr_pd + ICQ5_CL_HDRSIZE,
2172 offset + ICQ5_CL_HDRSIZE,
2173 pktsize - ICQ5_CL_HDRSIZE);
2175 case CMD_STATUS_CHANGE:
2176 icqv5_cmd_status_change(icq_tree,
2177 decr_pd + ICQ5_CL_HDRSIZE,
2178 offset + ICQ5_CL_HDRSIZE,
2179 pktsize - ICQ5_CL_HDRSIZE);
2181 case CMD_ACK_MESSAGES:
2182 icqv5_cmd_ack_messages(icq_tree,
2183 decr_pd + ICQ5_CL_HDRSIZE,
2184 offset + ICQ5_CL_HDRSIZE,
2185 pktsize - ICQ5_CL_HDRSIZE);
2187 case CMD_KEEP_ALIVE:
2188 icqv5_cmd_keep_alive(icq_tree,
2189 decr_pd + ICQ5_CL_HDRSIZE,
2190 offset + ICQ5_CL_HDRSIZE,
2191 pktsize - ICQ5_CL_HDRSIZE);
2193 case CMD_ADD_TO_LIST:
2194 icqv5_cmd_add_to_list(icq_tree,
2195 decr_pd + ICQ5_CL_HDRSIZE,
2196 offset + ICQ5_CL_HDRSIZE,
2197 pktsize - ICQ5_CL_HDRSIZE);
2199 case CMD_CONTACT_LIST:
2200 icqv5_cmd_contact_list(icq_tree,
2201 decr_pd + ICQ5_CL_HDRSIZE,
2202 offset + ICQ5_CL_HDRSIZE,
2203 pktsize - ICQ5_CL_HDRSIZE);
2206 case CMD_REG_NEW_USER:
2207 case CMD_QUERY_SERVERS:
2208 case CMD_QUERY_ADDONS:
2209 icqv5_cmd_no_params(icq_tree,
2210 decr_pd + ICQ5_CL_HDRSIZE,
2211 offset + ICQ5_CL_HDRSIZE,
2212 pktsize - ICQ5_CL_HDRSIZE,
2216 proto_tree_add_uint_format(icq_tree,
2223 cmd, findClientCmd(cmd));
2224 fprintf(stderr,"Missing: %s\n", findClientCmd(cmd));
2227 ti = proto_tree_add_text(icq_tree, NullTVB,
2231 icq_decode_tree = proto_item_add_subtree(ti,
2233 proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
2239 dissect_icqv5Server(const u_char *pd,
2245 /* Server traffic is easy, not encrypted */
2246 proto_tree *icq_tree = NULL;
2247 proto_tree *icq_header_tree = NULL;
2248 proto_item *ti = NULL;
2249 const u_char* decr_pd;
2250 int changeCol = (pktsize==(guint32)-1);
2252 guint16 version, cmd;
2253 guint32 uin, sessionid;
2254 guint16 seqnum1, seqnum2;
2257 uin = pletohl(&pd[ICQ5_SRV_UIN]);
2258 sessionid = pletohl(&pd[ICQ5_SRV_SESSIONID]);
2259 cmd = pletohs(&pd[ICQ5_SRV_CMD]);
2260 version = pletohs(&pd[ICQ_VERSION]);
2261 checkcode = pletohl(&pd[ICQ5_SRV_CHECKCODE]);
2262 seqnum1 = pletohs(&pd[ICQ5_SRV_SEQNUM1]);
2263 seqnum2 = pletohs(&pd[ICQ5_SRV_SEQNUM2]);
2265 pktsize = END_OF_FRAME;
2268 if (changeCol && check_col(fd, COL_INFO))
2269 col_add_fstr(fd, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
2272 ti = proto_tree_add_protocol_format(tree,
2277 "ICQv5 %s (len %u)",
2281 icq_tree = proto_item_add_subtree(ti, ett_icq);
2283 ti = proto_tree_add_uint_format(icq_tree,
2290 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
2292 proto_tree_add_text(icq_header_tree, NullTVB,
2293 offset + ICQ_VERSION,
2295 "Version: %u", version);
2296 proto_tree_add_uint_format(icq_header_tree,
2299 offset+ICQ5_SRV_SESSIONID,
2302 "Session ID: 0x%08x",
2304 proto_tree_add_text(icq_header_tree, NullTVB,
2305 offset + ICQ5_SRV_CMD,
2307 "Command: %s (%u)", findServerCmd(cmd), cmd);
2308 proto_tree_add_text(icq_header_tree, NullTVB,
2309 offset + ICQ5_SRV_SEQNUM1,
2311 "Seq Number 1: 0x%04x", seqnum1);
2312 proto_tree_add_text(icq_header_tree, NullTVB,
2313 offset + ICQ5_SRV_SEQNUM2,
2315 "Seq Number 2: 0x%04x", seqnum2);
2316 proto_tree_add_uint_format(icq_header_tree,
2319 offset+ICQ5_SRV_UIN,
2324 proto_tree_add_uint_format(icq_header_tree,
2327 offset+ICQ5_SRV_CHECKCODE,
2330 "Checkcode: 0x%08x",
2334 icqv5_srv_rand_user(icq_tree,
2335 decr_pd + ICQ5_SRV_HDRSIZE,
2336 offset + ICQ5_SRV_HDRSIZE,
2337 pktsize - ICQ5_SRV_HDRSIZE);
2339 case SRV_SYS_DELIVERED_MESS:
2340 /* The message structures are all the same. Why not run
2341 * the same routine? */
2342 icqv5_cmd_send_msg(icq_tree,
2343 decr_pd + ICQ5_SRV_HDRSIZE,
2344 offset + ICQ5_SRV_HDRSIZE,
2345 pktsize - ICQ5_SRV_HDRSIZE,
2348 case SRV_USER_ONLINE:
2349 icqv5_srv_user_online(icq_tree,
2350 decr_pd + ICQ5_SRV_HDRSIZE,
2351 offset + ICQ5_SRV_HDRSIZE,
2352 pktsize - ICQ5_SRV_HDRSIZE);
2354 case SRV_USER_OFFLINE:
2355 icqv5_srv_user_offline(icq_tree,
2356 decr_pd + ICQ5_SRV_HDRSIZE,
2357 offset + ICQ5_SRV_HDRSIZE,
2358 pktsize - ICQ5_SRV_HDRSIZE);
2360 case SRV_LOGIN_REPLY:
2361 icqv5_srv_login_reply(icq_tree,
2362 decr_pd + ICQ5_SRV_HDRSIZE,
2363 offset + ICQ5_SRV_HDRSIZE,
2364 pktsize - ICQ5_SRV_HDRSIZE);
2367 icqv5_srv_meta_user(icq_tree,
2368 decr_pd + ICQ5_SRV_HDRSIZE,
2369 offset + ICQ5_SRV_HDRSIZE,
2370 pktsize - ICQ5_SRV_HDRSIZE);
2372 case SRV_RECV_MESSAGE:
2373 icqv5_srv_recv_message(icq_tree,
2374 decr_pd + ICQ5_SRV_HDRSIZE,
2375 offset + ICQ5_SRV_HDRSIZE,
2376 pktsize - ICQ5_SRV_HDRSIZE);
2379 icqv5_srv_multi(icq_tree,
2380 decr_pd + ICQ5_SRV_HDRSIZE,
2381 offset + ICQ5_SRV_HDRSIZE,
2382 pktsize - ICQ5_SRV_HDRSIZE,
2386 case SRV_SILENT_TOO_LONG:
2390 case SRV_UPDATE_SUCCESS:
2391 icqv5_srv_no_params(icq_tree,
2392 decr_pd + ICQ5_SRV_HDRSIZE,
2393 offset + ICQ5_SRV_HDRSIZE,
2394 pktsize - ICQ5_SRV_HDRSIZE,
2398 proto_tree_add_uint_format(icq_tree,
2401 offset + ICQ5_SRV_CMD,
2405 cmd, findServerCmd(cmd));
2406 fprintf(stderr,"Missing: %s\n", findServerCmd(cmd));
2412 static void dissect_icqv5(const u_char *pd,
2417 guint32 unknown = pletohl(&pd[offset + ICQ5_UNKNOWN]);
2419 if (check_col(fd, COL_PROTOCOL))
2420 col_set_str(fd, COL_PROTOCOL, "ICQv5 (UDP)");
2421 if (check_col(fd, COL_INFO))
2422 col_set_str(fd, COL_INFO, "ICQv5 packet");
2423 if (unknown == 0x0L) {
2424 dissect_icqv5Client(pd, offset, fd, tree);
2426 dissect_icqv5Server(pd + offset, offset, fd, tree, (guint32) -1);
2430 static void dissect_icq(const u_char *pd,
2437 OLD_CHECK_DISPLAY_AS_DATA(proto_icq, pd, offset, fd, tree);
2439 version = pletohs(&pd[offset + ICQ_VERSION]);
2442 dissect_icqv5(pd, offset, fd, tree);
2445 dissect_icqv4(pd, offset, fd, tree);
2448 dissect_icqv3(pd, offset, fd, tree);
2451 dissect_icqv2(pd, offset, fd, tree);
2454 fprintf(stderr, "ICQ: Unknown version (%d)\n", version);
2459 /* registration with the filtering engine */
2461 proto_register_icq(void)
2463 static hf_register_info hf[] = {
2465 {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2467 {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, ""}},
2468 { &hf_icq_sessionid,
2469 {"SessionID", "icq.sessionid", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2471 {"Command", "icq.cmd", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2472 { &hf_icq_checkcode,
2473 {"Checkcode", "icq.checkcode", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2475 {"Decode", "icq.decode", FT_STRING, BASE_NONE, NULL, 0x0, ""}}
2477 static gint *ett[] = {
2482 &ett_icq_body_parts,
2485 proto_icq = proto_register_protocol ("ICQ Protocol", "icq");
2487 proto_register_field_array(proto_icq, hf, array_length(hf));
2489 proto_register_subtree_array(ett, array_length(ett));
2493 proto_reg_handoff_icq(void)
2495 old_dissector_add("udp.port", UDP_PORT_ICQ, dissect_icq);