2 * Routines for ICQ packet disassembly
4 * $Id: packet-icq.c,v 1.13 2000/03/14 07:12:23 gram Exp $
6 * Ethereal - Network traffic analyzer
8 * Copyright 1999 Johan Feyaerts
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 * This file: by Kojak <kojak@bigwig.net>
27 * Decoding code ripped, reference to the original author at the
28 * appropriate place with the code itself.
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
39 #ifdef HAVE_NETINET_IN_H
40 #include <netinet/in.h>
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
59 #ifdef NEED_SNPRINTF_H
65 # include "snprintf.h"
71 static int proto_icq = -1;
72 static int hf_icq_uin =-1;
73 static int hf_icq_cmd =-1;
74 static int hf_icq_sessionid =-1;
75 static int hf_icq_checkcode =-1;
76 static int hf_icq_decode = -1;
77 static int hf_icq_type = -1;
79 static gint ett_icq = -1;
80 static gint ett_icq_header = -1;
81 static gint ett_icq_decode = -1;
82 static gint ett_icq_body = -1;
83 static gint ett_icq_body_parts = -1;
85 enum { ICQ5_client, ICQ5_server};
87 void dissect_icqv5(const u_char *pd,
93 dissect_icqv5Server(const u_char *pd,
99 /* Offsets of fields in the ICQ headers */
100 /* Can be 0x0002 or 0x0005 */
101 #define ICQ_VERSION 0x00
102 /* Is either one (server) or four (client) bytes long */
103 /* Client header offsets */
104 #define ICQ5_UNKNOWN 0x02
105 #define ICQ5_CL_UIN 0x06
106 #define ICQ5_CL_SESSIONID 0x0a
107 #define ICQ5_CL_CMD 0x0e
108 #define ICQ5_CL_SEQNUM1 0x10
109 #define ICQ5_CL_SEQNUM2 0x12
110 #define ICQ5_CL_CHECKCODE 0x14
111 #define ICQ5_CL_PARAM 0x18
112 #define ICQ5_CL_HDRSIZE 0x18
114 /* Server header offsets */
115 #define ICQ5_SRV_SESSIONID 0x03
116 #define ICQ5_SRV_CMD 0x07
117 #define ICQ5_SRV_SEQNUM1 0x09
118 #define ICQ5_SRV_SEQNUM2 0x0b
119 #define ICQ5_SRV_UIN 0x0d
120 #define ICQ5_SRV_CHECKCODE 0x11
121 #define ICQ5_SRV_PARAM 0x15
122 #define ICQ5_SRV_HDRSIZE 0x15
124 typedef struct _cmdcode {
129 #define SRV_ACK 0x000a
131 #define SRV_GO_AWAY 0x0028
133 #define SRV_NEW_UIN 0x0046
135 /* LOGIN_REPLY is very scary. It has a lot of fields that are undocumented
136 * Only the IP field makes sense */
137 #define SRV_LOGIN_REPLY 0x005a
138 #define SRV_LOGIN_REPLY_IP 0x000c
140 #define SRV_BAD_PASS 0x0064
142 #define SRV_USER_ONLINE 0x006e
143 #define SRV_USER_ONL_UIN 0x0000
144 #define SRV_USER_ONL_IP 0x0004
145 #define SRV_USER_ONL_PORT 0x0008
146 #define SRV_USER_ONL_REALIP 0x000c
147 #define SRV_USER_ONL_X1 0x0010
148 #define SRV_USER_ONL_STATUS 0x0013
149 #define SRV_USER_ONL_X2 0x0015
151 #define SRV_USER_OFFLINE 0x0078
152 #define SRV_USER_OFFLINE_UIN 0x0000
154 #define SRV_MULTI 0x0212
155 #define SRV_MULTI_NUM 0x0000
157 #define SRV_META_USER 0x03de
158 #define SRV_META_USER_SUBCMD 0x0000
159 #define SRV_META_USER_RESULT 0x0002
160 #define SRV_META_USER_DATA 0x0003
162 #define SRV_UPDATE_SUCCESS 0x01e0
164 #define SRV_UPDATE_FAIL 0x01ea
167 * ICQv5 SRV_META_USER subcommands
169 #define META_EX_USER_FOUND 0x0190
170 #define META_USER_FOUND 0x019a
171 #define META_ABOUT 0x00e6
172 #define META_USER_INFO 0x00c8
174 #define SRV_RECV_MESSAGE 0x00dc
175 #define SRV_RECV_MSG_UIN 0x0000
176 #define SRV_RECV_MSG_YEAR 0x0004
177 #define SRV_RECV_MSG_MONTH 0x0006
178 #define SRV_RECV_MSG_DAY 0x0007
179 #define SRV_RECV_MSG_HOUR 0x0008
180 #define SRV_RECV_MSG_MINUTE 0x0009
181 #define SRV_RECV_MSG_MSG_TYPE 0x000a
183 #define SRV_RAND_USER 0x024e
184 #define SRV_RAND_USER_UIN 0x0000
185 #define SRV_RAND_USER_IP 0x0004
186 #define SRV_RAND_USER_PORT 0x0008
187 #define SRV_RAND_USER_REAL_IP 0x000c
188 #define SRV_RAND_USER_CLASS 0x0010
189 #define SRV_RAND_USER_X1 0x0011
190 #define SRV_RAND_USER_STATUS 0x0015
191 #define SRV_RAND_USER_TCP_VER 0x0019
193 /* This message has the same structure as cmd_send_msg */
194 #define SRV_SYS_DELIVERED_MESS 0x0104
196 cmdcode serverMetaSubCmdCode[] = {
197 { "META_USER_FOUND", META_USER_FOUND },
198 { "META_EX_USER_FOUND", META_EX_USER_FOUND },
199 { "META_ABOUT", META_ABOUT },
200 { "META_USER_INFO", META_USER_INFO },
204 cmdcode serverCmdCode[] = {
205 { "SRV_ACK", SRV_ACK },
206 { "SRV_GO_AWAY", SRV_GO_AWAY },
207 { "SRV_NEW_UIN", SRV_NEW_UIN },
208 { "SRV_LOGIN_REPLY", SRV_LOGIN_REPLY },
209 { "SRV_BAD_PASS", SRV_BAD_PASS },
210 { "SRV_USER_ONLINE", SRV_USER_ONLINE },
211 { "SRV_USER_OFFLINE", SRV_USER_OFFLINE },
212 { "SRV_QUERY", 130 },
213 { "SRV_USER_FOUND", 140 },
214 { "SRV_END_OF_SEARCH", 160 },
215 { "SRV_NEW_USER", 180 },
216 { "SRV_UPDATE_EXT", 200 },
217 { "SRV_RECV_MESSAGE", SRV_RECV_MESSAGE },
219 { "SRV_NOT_CONNECTED", 240 },
220 { "SRV_TRY_AGAIN", 250 },
221 { "SRV_SYS_DELIVERED_MESS", SRV_SYS_DELIVERED_MESS },
222 { "SRV_INFO_REPLY", 280 },
223 { "SRV_EXT_INFO_REPLY", 290 },
224 { "SRV_STATUS_UPDATE", 420 },
225 { "SRV_SYSTEM_MESSAGE", 450 },
226 { "SRV_UPDATE_SUCCESS", SRV_UPDATE_SUCCESS },
227 { "SRV_UPDATE_FAIL", SRV_UPDATE_FAIL },
228 { "SRV_AUTH_UPDATE", 500 },
229 { "SRV_MULTI_PACKET", SRV_MULTI },
231 { "SRV_RAND_USER", SRV_RAND_USER },
232 { "SRV_META_USER", SRV_META_USER },
236 #define MSG_TEXT 0x0001
237 #define MSG_URL 0x0004
238 #define MSG_AUTH_REQ 0x0006
239 #define MSG_AUTH 0x0008
240 #define MSG_USER_ADDED 0x000c
241 #define MSG_EMAIL 0x000e
242 #define MSG_CONTACTS 0x0013
244 #define STATUS_ONLINE 0x00000000
245 #define STATUS_AWAY 0x00000001
246 #define STATUS_DND 0x00000013
247 #define STATUS_INVISIBLE 0x00000100
248 #define STATUS_OCCUPIED 0x00000010
249 #define STATUS_NA 0x00000004
250 #define STATUS_CHAT 0x00000020
252 /* Offsets for all packets measured from the start of the payload; i.e.
253 * with the ICQ header removed
255 #define CMD_ACK 0x000a
256 #define CMD_ACK_RANDOM 0x0000
258 #define CMD_SEND_MSG 0x010E
259 #define CMD_SEND_MSG_RECV_UIN 0x0000
260 #define CMD_SEND_MSG_MSG_TYPE 0x0004
261 #define CMD_SEND_MSG_MSG_LEN 0x0006
262 #define CMD_SEND_MSG_MSG_TEXT 0x0008
263 /* The rest of the packet should be a null-term string */
265 #define CMD_LOGIN 0x03E8
266 #define CMD_LOGIN_TIME 0x0000
267 #define CMD_LOGIN_PORT 0x0004
268 #define CMD_LOGIN_PASSLEN 0x0008
269 #define CMD_LOGIN_PASSWD 0x000A
270 /* The password is variable length; so when we've decoded the passwd,
271 * the structure starts counting at 0 again.
273 #define CMD_LOGIN_IP 0x0004
274 #define CMD_LOGIN_STATUS 0x0009
276 #define CMD_CONTACT_LIST 0x0406
277 #define CMD_CONTACT_LIST_NUM 0x0000
279 #define CMD_USER_META 0x064a
281 #define CMD_REG_NEW_USER 0x03fc
283 #define CMD_ACK_MESSAGES 0x0442
284 #define CMD_ACK_MESSAGES_RANDOM 0x0000
286 #define CMD_KEEP_ALIVE 0x042e
287 #define CMD_KEEP_ALIVE_RANDOM 0x0000
289 #define CMD_SEND_TEXT_CODE 0x0438
290 #define CMD_SEND_TEXT_CODE_LEN 0x0000
291 #define CMD_SEND_TEXT_CODE_TEXT 0x0002
293 #define CMD_MSG_TO_NEW_USER 0x0456
295 #define CMD_QUERY_SERVERS 0x04ba
297 #define CMD_QUERY_ADDONS 0x04c4
299 #define CMD_STATUS_CHANGE 0x04d8
300 #define CMD_STATUS_CHANGE_STATUS 0x0000
302 #define CMD_ADD_TO_LIST 0x053c
303 #define CMD_ADD_TO_LIST_UIN 0x0000
305 #define CMD_RAND_SEARCH 0x056e
306 #define CMD_RAND_SEARCH_GROUP 0x0000
308 #define CMD_META_USER 0x064a
310 cmdcode msgTypeCode[] = {
311 { "MSG_TEXT", MSG_TEXT },
312 { "MSG_URL", MSG_URL },
313 { "MSG_AUTH_REQ", MSG_AUTH_REQ },
314 { "MSG_AUTH", MSG_AUTH },
315 { "MSG_USER_ADDED", MSG_USER_ADDED},
316 { "MSG_EMAIL", MSG_EMAIL},
317 { "MSG_CONTACTS", MSG_CONTACTS},
321 cmdcode statusCode[] = {
322 { "ONLINE", STATUS_ONLINE },
323 { "AWAY", STATUS_AWAY },
324 { "DND", STATUS_DND },
325 { "INVISIBLE", STATUS_INVISIBLE },
326 { "OCCUPIED", STATUS_OCCUPIED },
328 { "Free for Chat", STATUS_CHAT },
332 cmdcode clientCmdCode[] = {
333 { "CMD_ACK", CMD_ACK },
334 { "CMD_SEND_MESSAGE", CMD_SEND_MSG },
335 { "CMD_LOGIN", CMD_LOGIN },
336 { "CMD_REG_NEW_USER", CMD_REG_NEW_USER },
337 { "CMD_CONTACT_LIST", 1030 },
338 { "CMD_SEARCH_UIN", 1050 },
339 { "CMD_SEARCH_USER", 1060 },
340 { "CMD_KEEP_ALIVE", 1070 },
341 { "CMD_SEND_TEXT_CODE", CMD_SEND_TEXT_CODE },
342 { "CMD_ACK_MESSAGES", CMD_ACK_MESSAGES },
343 { "CMD_LOGIN_1", 1100 },
344 { "CMD_MSG_TO_NEW_USER", CMD_MSG_TO_NEW_USER },
345 { "CMD_INFO_REQ", 1120 },
346 { "CMD_EXT_INFO_REQ", 1130 },
347 { "CMD_CHANGE_PW", 1180 },
348 { "CMD_NEW_USER_INFO", 1190 },
349 { "CMD_UPDATE_EXT_INFO", 1200 },
350 { "CMD_QUERY_SERVERS", CMD_QUERY_SERVERS },
351 { "CMD_QUERY_ADDONS", CMD_QUERY_ADDONS },
352 { "CMD_STATUS_CHANGE", CMD_STATUS_CHANGE },
353 { "CMD_NEW_USER_1", 1260 },
354 { "CMD_UPDATE_INFO", 1290 },
355 { "CMD_AUTH_UPDATE", 1300 },
356 { "CMD_KEEP_ALIVE2", 1310 },
357 { "CMD_LOGIN_2", 1320 },
358 { "CMD_ADD_TO_LIST", CMD_ADD_TO_LIST },
359 { "CMD_RAND_SET", 1380 },
360 { "CMD_RAND_SEARCH", CMD_RAND_SEARCH },
361 { "CMD_META_USER", CMD_META_USER },
362 { "CMD_INVIS_LIST", 1700 },
363 { "CMD_VIS_LIST", 1710 },
364 { "CMD_UPDATE_LIST", 1720 },
369 * All ICQv5 decryption code thanx to Sebastien Dault (daus01@gel.usherb.ca)
373 0x59, 0x60, 0x37, 0x6B, 0x65, 0x62, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x60, 0x57, 0x5B, 0x3D,
374 0x5E, 0x34, 0x6D, 0x36, 0x50, 0x3F, 0x6F, 0x67, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x47, 0x63, 0x39,
375 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x43, 0x69, 0x48, 0x33, 0x31, 0x64, 0x35, 0x5A, 0x4A, 0x42,
376 0x56, 0x40, 0x67, 0x53, 0x41, 0x07, 0x6C, 0x49, 0x58, 0x3B, 0x4D, 0x46, 0x68, 0x43, 0x69, 0x48,
377 0x33, 0x31, 0x44, 0x65, 0x62, 0x46, 0x48, 0x53, 0x41, 0x07, 0x6C, 0x69, 0x48, 0x33, 0x51, 0x54,
378 0x5D, 0x4E, 0x6C, 0x49, 0x38, 0x4B, 0x55, 0x4A, 0x62, 0x46, 0x48, 0x33, 0x51, 0x34, 0x6D, 0x36,
379 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x63, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64, 0x35, 0x5A,
380 0x6A, 0x52, 0x6E, 0x3C, 0x51, 0x34, 0x6D, 0x36, 0x50, 0x5F, 0x5F, 0x3F, 0x4F, 0x37, 0x4B, 0x35,
381 0x5A, 0x4A, 0x62, 0x66, 0x58, 0x3B, 0x4D, 0x66, 0x58, 0x5B, 0x5D, 0x4E, 0x6C, 0x49, 0x58, 0x3B,
382 0x4D, 0x66, 0x58, 0x3B, 0x4D, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64,
383 0x55, 0x6A, 0x32, 0x3E, 0x44, 0x45, 0x52, 0x6E, 0x3C, 0x31, 0x64, 0x55, 0x6A, 0x52, 0x4E, 0x6C,
384 0x69, 0x48, 0x53, 0x61, 0x4C, 0x39, 0x30, 0x6F, 0x47, 0x63, 0x59, 0x60, 0x57, 0x5B, 0x3D, 0x3E,
385 0x64, 0x35, 0x3A, 0x3A, 0x5A, 0x6A, 0x52, 0x4E, 0x6C, 0x69, 0x48, 0x53, 0x61, 0x6C, 0x49, 0x58,
386 0x3B, 0x4D, 0x46, 0x68, 0x63, 0x39, 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x67, 0x53, 0x41, 0x25, 0x41,
387 0x3C, 0x51, 0x54, 0x3D, 0x5E, 0x54, 0x5D, 0x4E, 0x4C, 0x39, 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F,
388 0x47, 0x43, 0x69, 0x48, 0x33, 0x51, 0x54, 0x5D, 0x6E, 0x3C, 0x31, 0x64, 0x35, 0x5A, 0x00, 0x00 };
391 findcmd(cmdcode* c, int num)
395 while (p->descr != NULL) {
396 if (p->code == num) {
401 snprintf(buf, sizeof(buf), "(%x)", num);
408 return findcmd(msgTypeCode, num);
414 return findcmd(serverMetaSubCmdCode, num);
418 findClientCmd(int num)
420 return findcmd(clientCmdCode, num);
424 findServerCmd(int num)
426 return findcmd(serverCmdCode, num);
432 return findcmd(statusCode, num);
436 proto_tree_add_hexdump(proto_tree* t,
444 int done = 0, line = 0;
452 for (i=0;i<line;i++) {
455 for (n = i * 16; n < (i+1)*16; n++) {
456 added = sprintf(buf+done, "%02x", data[n]);
458 added += sprintf(buf + done + added, " ");
460 added += sprintf(buf + done + added, " ");
463 for (n = i * 16; n < (i+1)*16; n++) {
464 if (isprint(data[n]))
465 added = sprintf(buf + done, "%c", data[n]);
467 added = sprintf(buf + done, ".");
470 proto_tree_add_text(t,
477 for (n = line * 16 ; n < size ; n++) {
478 added = sprintf(buf+done, "%02x", data[n]);
480 added += sprintf(buf + done + added, " ");
482 added += sprintf(buf + done + added, " ");
485 for (n = size ; (n%16)!=0;n++) {
488 added += sprintf(buf + done + added, " ");
490 added += sprintf(buf + done + added, " ");
493 for (n = line * 16; n < (line+1)*16; n++) {
496 if (isprint(data[n]))
497 added = sprintf(buf + done, "%c", data[n]);
499 added = sprintf(buf + done, ".");
501 added = sprintf(buf + done, " ");
505 proto_tree_add_text(t,
513 get_v5key(const u_char* pd, int len)
515 guint32 a1, a2, a3, a4, a5;
516 guint32 code, check, key;
518 code = pletohl(&pd[ICQ5_CL_CHECKCODE]);
520 a1 = code & 0x0001f000;
521 a2 = code & 0x07c007c0;
522 a3 = code & 0x003e0001;
523 a4 = code & 0xf8000000;
524 a5 = code & 0x0000083e;
532 check = a5 + a1 + a2 + a3 + a4;
533 key = len * 0x68656C6C;
539 decrypt_v5(u_char *bfr, guint32 size,guint32 key)
543 for (i=0x0a; i < size+3; i+=4 ) {
544 k = key+table_v5[i&0xff];
546 bfr[i] ^= (u_char)(k & 0xff);
547 bfr[i+1] ^= (u_char)((k & 0xff00)>>8);
550 bfr[i+2] ^= (u_char)((k & 0xff0000)>>16);
551 bfr[i+3] ^= (u_char)((k & 0xff000000)>>24);
557 dissect_icqv2(const u_char *pd,
562 /* Not really implemented yet */
563 if (check_col(fd, COL_PROTOCOL)) {
564 col_add_str(fd, COL_PROTOCOL, "ICQv2 (UDP)");
566 if (check_col(fd, COL_INFO)) {
567 col_add_str(fd, COL_INFO, "ICQ Version 2 protocol");
572 * Find first occurrence of ch in buf
573 * Buf is max size big.
576 strnchr(const u_char* buf, u_char ch, int size)
579 u_char* p = (u_char*) buf;
580 for (i=0;(*p) && (*p!=ch) && (i<size); p++, i++)
582 if ((*p == '\0') || (i>=size))
588 * The packet at pd has a (len, string) pair.
589 * Copy the string to a buffer, and display it in the tree.
590 * Observe any limits you might cross.
592 * If anything is wrong, return -1, since -1 is not a valid string
593 * length. Else, return the number of chars processed.
596 proto_add_icq_attr(proto_tree* tree, /* The tree to add to */
597 const char* pd, /* Pointer to the field */
598 const int offset, /* Offset from the start of packet */
599 const int size, /* The number of bytes left in pd */
600 char* descr) /* The description to use in the tree */
606 if (size<sizeof(guint16))
609 left -= sizeof(guint16);
611 proto_tree_add_text(tree,
618 data = g_malloc(len);
620 strncpy(data, pd + sizeof(guint16), len);
621 data[len - 1] = '\0';
623 proto_tree_add_text(tree,
625 sizeof(guint16) + len,
626 "%s[%u]: %s", descr, len, data);
629 return len + sizeof(guint16);
633 icqv5_decode_msgType(proto_tree* tree,
634 const unsigned char* pd, /* From start of messageType */
638 proto_item* ti = NULL;
639 proto_tree* subtree = NULL;
641 char *msgText = NULL;
642 guint16 msgType = -1;
645 static char* auth_req_field_descr[] = {
652 static char* emain_field_descr[] = {
661 enum {OFF_MSG_TYPE=0,
666 if (left >= sizeof(guint16)) {
667 msgType = pletohs(pd + OFF_MSG_TYPE);
668 left -= sizeof(guint16);
670 if (left >= sizeof(guint16)) {
671 msgLen = pletohs(pd + OFF_MSG_LEN);
672 left -= sizeof(guint16);
675 ti = proto_tree_add_text(tree,
678 "Type: %u (%s)", msgType, findMsgType(msgType));
679 /* Create a new subtree */
680 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
683 case 0xffff: /* Field unknown */
686 fprintf(stderr, "Unknown msgType: %u (%04x)\n", msgType, msgType);
689 msgText = g_malloc(left + 1);
690 strncpy(msgText, pd + OFF_MSG_TEXT, left);
691 msgText[left] = '\0';
692 proto_tree_add_text(subtree,
693 offset + OFF_MSG_TEXT,
699 /* Two parts, a description and the URL. Separeted by FE */
700 for (i=0;i<left;i++) {
701 if (pd[OFF_MSG_TEXT + i] == 0xfe)
704 msgText = g_malloc(i + 1);
705 strncpy(msgText, pd + OFF_MSG_TEXT, i);
710 proto_tree_add_text(subtree,
711 offset + OFF_MSG_TEXT,
713 "Description: %s", msgText);
716 msgText = g_realloc(msgText, left - i);
717 strncpy(msgText, pd + OFF_MSG_TEXT + i + 1, left - i - 1);
718 msgText[left - i] = '\0';
719 proto_tree_add_text(subtree,
720 offset + OFF_MSG_TEXT,
729 for (n = 0; n < 6; n++) {
731 (i<left) && (pd[OFF_MSG_TEXT+i]!=0xfe);
735 msgText = g_realloc(msgText, i-j);
736 strncpy(msgText, pd + OFF_MSG_TEXT + j, i - j - 1);
737 msgText[i-j-1] = '\0';
738 proto_tree_add_text(subtree,
739 offset + OFF_MSG_TEXT + j,
741 "%s: %s", emain_field_descr[n], msgText);
743 proto_tree_add_text(subtree,
744 offset + OFF_MSG_TEXT + j,
746 "%s: %s", emain_field_descr[n], "(empty)");
756 /* Three bytes, first is a char signifying success */
757 unsigned char auth_suc = pd[OFF_MSG_LEN];
758 guint16 x1 = pd[OFF_MSG_LEN+1];
759 proto_tree_add_text(subtree,
760 offset + OFF_MSG_LEN,
762 "Authorization: (%u) %s",auth_suc,
763 (auth_suc==0)?"Denied":"Allowed");
764 proto_tree_add_text(subtree,
765 offset + OFF_MSG_LEN + 1,
771 /* Six parts, separated by FE */
774 msgText = g_malloc(64);
775 for (n = 0; n < 6 && i<left; n++) {
776 while (i<left && pd[OFF_MSG_TEXT+i]!=0xfe)
779 /* pd[OFF_MSG_TEXT+i] == 0xfe */
781 /* Otherwise, it'd be a null string */
782 msgText = g_realloc(msgText, i - j);
783 strncpy(msgText, pd + OFF_MSG_TEXT + j, i-j);
785 proto_tree_add_text(subtree,
786 offset + OFF_MSG_TEXT + j,
788 "%s: %s", auth_req_field_descr[n], msgText);
790 proto_tree_add_text(subtree,
791 offset + OFF_MSG_TEXT + j,
793 "%s: %s", auth_req_field_descr[n], "(null)");
796 /* i and j point after the 0xfe character */
804 /* Four parts, separated by FE */
807 /* This is necessary, because g_realloc does not behave like
808 * g_malloc if the first parameter == NULL */
809 msgText = g_malloc(64);
810 for (n = 0; n < 4 && i<left; n++) {
811 while (i<left && pd[OFF_MSG_TEXT+i]!=0xfe)
814 /* pd[OFF_MSG_TEXT+i] == 0xfe */
816 /* Otherwise, it'd be a null string */
817 msgText = g_realloc(msgText, i - j);
818 strncpy(msgText, pd + OFF_MSG_TEXT + j, i-j);
820 proto_tree_add_text(subtree,
821 offset + OFF_MSG_TEXT + j,
823 "%s: %s", auth_req_field_descr[n], msgText);
825 proto_tree_add_text(subtree,
826 offset + OFF_MSG_TEXT + j,
828 "%s: %s", auth_req_field_descr[n], "(null)");
831 /* i and j point after the 0xfe character */
839 u_char* p = (u_char*) &pd[OFF_MSG_TEXT];
841 int sz = 0; /* Size of the current element */
842 int n = 0; /* The nth element */
843 int done = 0; /* Number of chars processed */
844 u_char* msgText2 = NULL;
846 /* Create a new subtree */
847 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
849 p = strnchr(pprev, 0xfe, left);
852 sz = (int)(p - pprev);
855 msgText = g_realloc(msgText, sz+1);
856 strncpy(msgText, pprev, sz);
860 /* The first element is the number of Nick/UIN pairs follow */
861 proto_tree_add_text(subtree,
862 offset + OFF_MSG_TEXT + done,
864 "Number of pairs: %s", msgText);
866 } else if (p!=NULL) {
870 p = strnchr(pprev, 0xfe, left);
872 sz = (int)(p - pprev);
875 msgText2 = g_malloc(sz+1);
876 strncpy(msgText2, pprev, sz);
879 proto_tree_add_text(subtree,
880 offset + OFF_MSG_TEXT + done,
882 "%s:%s", msgText, msgText2);
896 /*********************************
900 *********************************/
902 icqv5_cmd_ack(proto_tree* tree,/* Tree to put the data in */
903 const u_char* pd, /* Packet content */
904 int offset, /* Offset from the start of the packet to the content */
905 int size) /* Number of chars left to do */
907 guint32 random = pletohl(pd + CMD_ACK_RANDOM);
912 ti = proto_tree_add_uint_format(tree,
918 subtree = proto_item_add_subtree(ti, ett_icq_body);
919 proto_tree_add_text(subtree,
920 offset + CMD_ACK_RANDOM,
922 "Random: 0x%08x", random);
927 icqv5_cmd_rand_search(proto_tree* tree, /* Tree to put the data in */
928 const u_char* pd, /* Packet content */
929 int offset, /* Offset from the start of the packet to the content */
930 int size) /* Number of chars left to do */
932 guint16 group = pletohs(pd + CMD_RAND_SEARCH_GROUP);
936 static const char* groups[] = {
951 ti = proto_tree_add_uint_format(tree,
957 subtree = proto_item_add_subtree(ti, ett_icq_body);
958 if (group>0 && (group<=sizeof(groups)/sizeof(const char*)))
959 proto_tree_add_text(subtree,
960 offset + CMD_RAND_SEARCH_GROUP,
962 "Group: (%u) %s", group, groups[group-1]);
964 proto_tree_add_text(subtree,
965 offset + CMD_RAND_SEARCH_GROUP,
967 "Group: (%u)", group);
972 icqv5_cmd_ack_messages(proto_tree* tree,/* Tree to put the data in */
973 const u_char* pd, /* Packet content */
974 int offset, /* Offset from the start of the packet to the content */
975 int size) /* Number of chars left to do */
977 guint32 random = pletohl(pd + CMD_ACK_MESSAGES_RANDOM);
982 ti = proto_tree_add_uint_format(tree,
988 subtree = proto_item_add_subtree(ti, ett_icq_body);
989 proto_tree_add_text(subtree,
990 offset + CMD_ACK_MESSAGES_RANDOM,
992 "Random: 0x%08x", random);
997 icqv5_cmd_keep_alive(proto_tree* tree,/* Tree to put the data in */
998 const u_char* pd, /* Packet content */
999 int offset, /* Offset from the start of the packet to the content */
1000 int size) /* Number of chars left to do */
1002 guint32 random = pletohl(pd + CMD_KEEP_ALIVE_RANDOM);
1003 proto_tree* subtree;
1007 ti = proto_tree_add_uint_format(tree,
1013 subtree = proto_item_add_subtree(ti, ett_icq_body);
1014 proto_tree_add_text(subtree,
1015 offset + CMD_KEEP_ALIVE_RANDOM,
1017 "Random: 0x%08x", random);
1022 icqv5_cmd_send_text_code(proto_tree* tree,/* Tree to put the data in */
1023 const u_char* pd, /* Packet content */
1024 int offset, /* Offset from the start of the packet to the content */
1025 int size) /* Number of chars left to do */
1027 proto_tree* subtree = NULL;
1028 proto_item* ti = NULL;
1032 int left = size; /* The amount of data left to analyse */
1035 ti = proto_tree_add_uint_format(tree,
1043 if (left<sizeof(guint16))
1045 len = pletohs(pd+CMD_SEND_TEXT_CODE_LEN);
1046 left -= sizeof(gint16);
1048 subtree = proto_item_add_subtree(ti, ett_icq_body);
1049 proto_tree_add_text(subtree,
1050 offset + CMD_SEND_TEXT_CODE_LEN,
1056 len = MIN(len, left);
1057 text = g_malloc(len+1);
1058 memcpy(text, pd + CMD_SEND_TEXT_CODE_TEXT, len);
1062 proto_tree_add_text(subtree,
1063 offset + CMD_SEND_TEXT_CODE_TEXT,
1070 if (left<sizeof(gint16))
1073 x1 = pletohs(pd + size - left);
1074 left -= sizeof(gint16);
1076 proto_tree_add_text(subtree,
1077 offset + CMD_SEND_TEXT_CODE_TEXT + len,
1084 icqv5_cmd_add_to_list(proto_tree* tree,/* Tree to put the data in */
1085 const u_char* pd, /* Packet content */
1086 int offset, /* Offset from the start of the packet to the content */
1087 int size) /* Number of chars left to do */
1090 proto_tree* subtree;
1093 uin = pletohl(pd + CMD_ADD_TO_LIST);
1095 ti = proto_tree_add_uint_format(tree,
1101 subtree = proto_item_add_subtree(ti, ett_icq_body);
1102 proto_tree_add_text(subtree,
1103 offset + CMD_ADD_TO_LIST_UIN,
1110 icqv5_cmd_status_change(proto_tree* tree,/* Tree to put the data in */
1111 const u_char* pd, /* Packet content */
1112 int offset, /* Offset from the start of the packet to the content */
1113 int size) /* Number of chars left to do */
1115 guint32 status = -1;
1116 proto_tree* subtree;
1119 if (size >= CMD_STATUS_CHANGE_STATUS + 4)
1120 status = pletohl(pd + CMD_STATUS_CHANGE_STATUS);
1122 ti = proto_tree_add_uint_format(tree,
1128 subtree = proto_item_add_subtree(ti, ett_icq_body);
1130 proto_tree_add_text(subtree,
1131 offset + CMD_STATUS_CHANGE_STATUS,
1133 "Status: %08x (%s)", status, findStatus(status));
1138 icqv5_cmd_send_msg(proto_tree* tree,
1144 proto_tree* subtree;
1146 guint32 receiverUIN = 0xffffffff;
1147 guint16 msgType = 0xffff;
1148 guint16 msgLen = 0xffff;
1149 int left = size; /* left chars to do */
1153 receiverUIN = pletohl(pd + CMD_SEND_MSG_RECV_UIN);
1157 msgType = pletohs(pd + CMD_SEND_MSG_MSG_TYPE);
1161 msgLen = pletohs(pd + CMD_SEND_MSG_MSG_LEN);
1165 ti = proto_tree_add_uint_format(tree,
1171 subtree = proto_item_add_subtree(ti, ett_icq_body);
1172 proto_tree_add_text(subtree,
1173 offset + CMD_SEND_MSG_RECV_UIN,
1175 "Receiver UIN: %u", receiverUIN);
1176 proto_tree_add_text(subtree,
1177 offset + CMD_SEND_MSG_MSG_LEN,
1179 "Length: %u", msgLen);
1181 icqv5_decode_msgType(subtree,
1182 pd + CMD_SEND_MSG_MSG_TYPE,
1183 offset + CMD_SEND_MSG_MSG_TYPE,
1184 left+4); /* There are 4 bytes more... */
1189 icqv5_cmd_login(proto_tree* tree,
1195 proto_tree* subtree;
1196 time_t theTime = -1;
1198 guint32 passwdLen = -1;
1199 char* password = NULL;
1200 const u_char *ipAddrp = NULL;
1201 guint32 status = -1;
1202 guint32 left = size;
1205 theTime = pletohl(pd + CMD_LOGIN_TIME);
1208 port = pletohl(pd + CMD_LOGIN_PORT);
1211 passwdLen = pletohs(pd + CMD_LOGIN_PASSLEN);
1213 if (left>=10+passwdLen) {
1214 password = g_malloc(passwdLen + 1);
1215 strncpy(password, pd + CMD_LOGIN_PASSWD, passwdLen);
1216 password[passwdLen] = '\0';
1219 if (left>=10+passwdLen+CMD_LOGIN_IP+4) {
1220 ipAddrp = pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP;
1222 if (left>=10+passwdLen+CMD_LOGIN_STATUS+4) {
1223 status = pletohs(pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS);
1226 ti = proto_tree_add_uint_format(tree,
1232 subtree = proto_item_add_subtree(ti, ett_icq_body);
1234 proto_tree_add_text(subtree,
1235 offset + CMD_LOGIN_TIME,
1237 "Time: %ld = %s", (long)theTime, ctime(&theTime));
1239 proto_tree_add_text(subtree,
1240 offset + CMD_LOGIN_PORT,
1243 if ((passwdLen!=-1) && (password!=NULL))
1244 proto_tree_add_text(subtree,
1245 offset + CMD_LOGIN_PASSLEN,
1247 "Passwd: %s", password);
1249 proto_tree_add_text(subtree,
1250 offset + CMD_LOGIN_PASSWD + CMD_LOGIN_IP,
1252 "IP: %s", ip_to_str(ipAddrp));
1254 proto_tree_add_text(subtree,
1255 offset + CMD_LOGIN_PASSWD + CMD_LOGIN_IP,
1257 "Status: %s", findStatus(status));
1264 icqv5_cmd_contact_list(proto_tree* tree,
1269 proto_tree* subtree;
1271 unsigned char num = -1;
1274 const u_char* p = NULL;
1276 if (size >= CMD_CONTACT_LIST_NUM + 1)
1277 num = pd[CMD_CONTACT_LIST_NUM];
1280 ti = proto_tree_add_uint_format(tree,
1286 subtree = proto_item_add_subtree(ti, ett_icq_body);
1287 proto_tree_add_text(subtree,
1288 offset + CMD_CONTACT_LIST,
1290 "Number of uins: %u", num);
1292 * A sequence of num times UIN follows
1294 offset += (CMD_CONTACT_LIST_NUM + 1);
1296 p = &pd[CMD_CONTACT_LIST_NUM + 1];
1297 for (i = 0; (i<num) && (left>0);i++) {
1300 proto_tree_add_text(subtree,
1303 "UIN[%d]: %u",i,uin);
1313 icqv5_cmd_no_params(proto_tree* tree,/* Tree to put the data in */
1314 const u_char* pd, /* Packet content */
1315 int offset, /* Offset from the start of the packet to the content */
1316 int size, /* Number of chars left to do */
1319 proto_tree* subtree;
1323 ti = proto_tree_add_uint_format(tree,
1329 subtree = proto_item_add_subtree(ti, ett_icq_body);
1330 proto_tree_add_text(subtree,
1337 /**********************
1341 **********************
1344 icqv5_srv_no_params(proto_tree* tree,/* Tree to put the data in */
1345 const u_char* pd, /* Packet content */
1346 int offset, /* Offset from the start of the packet to the content */
1347 int size, /* Number of chars left to do */
1350 proto_tree* subtree;
1354 ti = proto_tree_add_uint_format(tree,
1360 subtree = proto_item_add_subtree(ti, ett_icq_body);
1361 proto_tree_add_text(subtree,
1369 icqv5_srv_login_reply(proto_tree* tree,/* Tree to put the data in */
1370 const u_char* pd, /* Packet content */
1371 int offset, /* Offset from the start of the packet to the content */
1372 int size) /* Number of chars left to do */
1374 proto_tree* subtree;
1376 const u_char *ipAddrp = NULL;
1378 if (size >= SRV_LOGIN_REPLY_IP + 4)
1379 ipAddrp = &pd[SRV_LOGIN_REPLY_IP];
1382 ti = proto_tree_add_uint_format(tree,
1385 SRV_LOGIN_REPLY_IP + 8,
1388 subtree = proto_item_add_subtree(ti, ett_icq_body);
1389 proto_tree_add_text(subtree,
1390 offset + SRV_LOGIN_REPLY_IP,
1392 "IP: %s", ip_to_str(ipAddrp));
1397 icqv5_srv_user_online(proto_tree* tree,/* Tree to put the data in */
1398 const u_char* pd, /* Packet content */
1399 int offset, /* Offset from the start of the packet to the content */
1400 int size) /* Number of chars left to do */
1402 proto_tree* subtree;
1405 const u_char *ipAddrp = NULL;
1407 const u_char *realipAddrp = NULL;
1408 guint32 status = -1;
1409 guint32 version = -1;
1411 if (size >= SRV_USER_ONL_UIN + 4)
1412 uin = pletohl(pd + SRV_USER_ONL_UIN);
1414 if (size >= SRV_USER_ONL_IP + 4)
1415 ipAddrp = &pd[SRV_USER_ONL_IP];
1417 if (size >= SRV_USER_ONL_PORT + 4)
1418 port = pletohl(pd + SRV_USER_ONL_PORT);
1420 if (size >= SRV_USER_ONL_REALIP + 4)
1421 realipAddrp = &pd[SRV_USER_ONL_REALIP];
1423 if (size >= SRV_USER_ONL_STATUS + 2)
1424 status = pletohs(pd + SRV_USER_ONL_STATUS);
1427 * Kojak: Hypothesis is that this field might be an encoding for the
1428 * version used by the UIN that changed. To test this, I included
1429 * this line to the code.
1431 if (size >= SRV_USER_ONL_X2 + 4)
1432 version = pletohl(pd + SRV_USER_ONL_X2);
1435 ti = proto_tree_add_uint_format(tree,
1438 SRV_LOGIN_REPLY_IP + 8,
1441 subtree = proto_item_add_subtree(ti, ett_icq_body);
1442 proto_tree_add_text(subtree,
1443 offset + SRV_USER_ONL_UIN,
1446 proto_tree_add_text(subtree,
1447 offset + SRV_USER_ONL_IP,
1449 "IP: %s", ip_to_str(ipAddrp));
1450 proto_tree_add_text(subtree,
1451 offset + SRV_USER_ONL_PORT,
1454 proto_tree_add_text(subtree,
1455 offset + SRV_USER_ONL_REALIP,
1457 "RealIP: %s", ip_to_str(realipAddrp));
1458 proto_tree_add_text(subtree,
1459 offset + SRV_USER_ONL_STATUS,
1461 "Status: %s", findStatus(status));
1462 proto_tree_add_text(subtree,
1463 offset + SRV_USER_ONL_X2,
1465 "Version: %08x", version);
1470 icqv5_srv_user_offline(proto_tree* tree,/* Tree to put the data in */
1471 const u_char* pd, /* Packet content */
1472 int offset, /* Offset from the start of the packet to the content */
1473 int size) /* Number of chars left to do */
1475 proto_tree* subtree;
1479 if (size >= SRV_USER_OFFLINE + 4)
1480 uin = pletohl(&pd[SRV_USER_OFFLINE]);
1483 ti = proto_tree_add_uint_format(tree,
1486 SRV_USER_OFFLINE_UIN + 4,
1489 subtree = proto_item_add_subtree(ti, ett_icq_body);
1490 proto_tree_add_text(subtree,
1491 offset + SRV_USER_OFFLINE_UIN,
1498 icqv5_srv_multi(proto_tree* tree,/* Tree to put the data in */
1499 const u_char* pd, /* Packet content */
1500 int offset, /* Offset from the start of the packet to the content */
1501 int size, /* Number of chars left to do */
1504 proto_tree* subtree;
1506 unsigned char num = -1;
1509 const u_char* p = NULL;
1511 if (size >= SRV_MULTI_NUM + 1)
1512 num = pd[SRV_MULTI_NUM];
1515 ti = proto_tree_add_uint_format(tree,
1521 subtree = proto_item_add_subtree(ti, ett_icq_body);
1522 proto_tree_add_text(subtree,
1523 offset + SRV_MULTI_NUM,
1525 "Number of pkts: %u", num);
1527 * A sequence of num times ( pktsize, packetData) follows
1529 offset += (SRV_MULTI_NUM + 1);
1531 p = &pd[SRV_MULTI_NUM + 1];
1532 for (i = 0; (i<num) && (left>0);i++) {
1539 dissect_icqv5Server(p, offset, fd, subtree, pktSz);
1550 icqv5_srv_meta_user(proto_tree* tree, /* Tree to put the data in */
1551 const u_char* pd, /* Packet content */
1552 int offset, /* Offset from the start of the packet to the content */
1553 int size) /* Number of chars left to do */
1556 proto_tree* subtree = NULL;
1558 proto_tree* sstree = NULL;
1559 proto_item* ti = NULL;
1563 guint16 subcmd = -1;
1564 unsigned char result = -1;
1566 if (size>=SRV_META_USER_SUBCMD + 2)
1567 subcmd = pletohs(pd+SRV_META_USER_SUBCMD);
1568 if (size>=SRV_META_USER_RESULT + 1)
1569 result = pd[SRV_META_USER_RESULT];
1573 ti = proto_tree_add_uint_format(tree,
1579 subtree = proto_item_add_subtree(ti, ett_icq_body);
1580 ti = proto_tree_add_text(subtree,
1581 offset + SRV_META_USER_SUBCMD,
1583 "%s", findSubCmd(subcmd));
1584 proto_tree_add_text(subtree,
1585 offset + SRV_META_USER_RESULT,
1587 "%s", (result==0x0a)?"Success":"Failure");
1588 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1590 ti = proto_tree_add_text(tree,
1591 offset + SRV_META_USER_SUBCMD,
1593 "%s", findSubCmd(subcmd));
1594 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1595 proto_tree_add_text(sstree,
1596 offset + SRV_META_USER_RESULT,
1598 "%s", (result==0x0a)?"Success":"Failure");
1601 /* Skip the META_USER header */
1606 case META_EX_USER_FOUND:
1608 /* This is almost the same as META_USER_FOUND,
1609 * however, there's an extra length field
1611 guint16 pktLen = -1;
1613 /* Read the lenght field */
1614 pktLen = pletohs(p);
1615 proto_tree_add_text(sstree,
1616 offset + size - left,
1618 "Length: %u", pktLen);
1620 p += sizeof(guint16); left -= sizeof(guint16);
1622 case META_USER_FOUND:
1624 /* The goto mentioned in this block should be local to this
1625 * block if C'd allow it.
1627 * They are used to "implement" a poorman's exception handling
1644 if (left<sizeof(guint32))
1647 proto_tree_add_text(sstree,
1648 offset + size - left,
1651 p+=sizeof(guint32);left-=sizeof(guint32);
1653 for ( ; *d!=NULL; d++) {
1654 len = proto_add_icq_attr(sstree,
1656 offset + size - left,
1661 p += len; left -= len;
1663 /* Get the authorize setting */
1664 if (left<sizeof(unsigned char))
1667 proto_tree_add_text(sstree,
1668 offset + size - left,
1670 "authorization: %s", (auth==0x01)?"Neccessary":"Who needs it");
1673 if (left<sizeof(guint16))
1676 proto_tree_add_text(sstree,
1677 offset + size - left,
1680 p+=sizeof(guint16);left-=sizeof(guint16);
1682 if (left<sizeof(guint32))
1685 proto_tree_add_text(sstree,
1686 offset + size - left,
1689 p+=sizeof(guint32);left-=sizeof(guint32);
1696 /* Get the about information */
1697 if (left<sizeof(guint16))
1700 p+=sizeof(guint16);left-=sizeof(guint16);
1701 if ((len<=0) || (left<len))
1703 about = g_malloc(len);
1704 strncpy(about, p, len);
1705 proto_tree_add_text(sstree,
1706 offset + size - left,
1707 sizeof(guint16)+len,
1708 "About(%d): %s", len, about);
1714 case META_USER_INFO:
1716 /* The goto mentioned in this block should be local to this
1717 * block if C'd allow it.
1719 * They are used to "implement" a poorman's exception handling
1721 static const char* descr[] = {
1736 const char** d = descr;
1739 unsigned char user_timezone = -1;
1740 unsigned char auth = -1;
1744 if (left<sizeof(guint32))
1747 proto_tree_add_text(sstree,
1748 offset + size - left,
1751 p+=sizeof(guint32);left-=sizeof(guint32);
1755 * Get every field from the description
1757 while ((*d)!=NULL) {
1758 if (left<sizeof(guint16))
1761 p+=sizeof(guint16);left-=sizeof(guint16);
1762 if ((len<0) || (left<len))
1765 item = g_malloc(len);
1766 strncpy(item, p, len);
1767 proto_tree_add_text(sstree,
1768 offset + size - left - sizeof(guint16),
1769 sizeof(guint16)+len,
1770 "%s(%d): %s",*d, len, item);
1776 /* Get country code */
1777 if (left<sizeof(guint16))
1779 country = pletohs(p);
1780 proto_tree_add_text(sstree,
1781 offset + size - left,
1783 "Countrycode: %u", country);
1784 p+=sizeof(guint16); left-=sizeof(guint16);
1785 /* Get the timezone setting */
1786 if (left<sizeof(unsigned char))
1789 proto_tree_add_text(sstree,
1790 offset + size - left,
1791 sizeof(unsigned char),
1792 "Timezone: %u", user_timezone);
1794 /* Get the authorize setting */
1795 if (left<sizeof(unsigned char))
1798 proto_tree_add_text(sstree,
1799 offset + size - left,
1800 sizeof(unsigned char),
1801 "Authorization: (%u) %s",
1802 auth, (auth==0)?"No":"Yes");
1804 /* Get the webaware setting */
1805 if (left<sizeof(unsigned char))
1808 proto_tree_add_text(sstree,
1809 offset + size - left,
1810 sizeof(unsigned char),
1811 "Webaware: (%u) %s",
1812 auth, (auth==0)?"No":"Yes");
1814 /* Get the authorize setting */
1815 if (left<sizeof(unsigned char))
1818 proto_tree_add_text(sstree,
1819 offset + size - left,
1820 sizeof(unsigned char),
1822 auth, (auth==0)?"No":"Yes");
1827 /* This information is already printed in the tree */
1828 fprintf(stderr, "Meta subcmd: %04x\n", subcmd);
1835 icqv5_srv_recv_message(proto_tree* tree, /* Tree to put the data in */
1836 const u_char* pd, /* Packet content */
1837 int offset, /* Offset from the start of the packet to the content */
1838 int size) /* Number of chars left to do */
1840 proto_tree* subtree = NULL;
1841 proto_item* ti = NULL;
1845 unsigned char month = -1;
1846 unsigned char day = -1;
1847 unsigned char hour = -1;
1848 unsigned char minute = -1;
1851 ti = proto_tree_add_uint_format(tree,
1857 subtree = proto_item_add_subtree(ti, ett_icq_body);
1858 if (left>=sizeof(guint32)) {
1859 uin = pletohl(pd + SRV_RECV_MSG_UIN);
1860 proto_tree_add_uint_format(subtree,
1862 offset + SRV_RECV_MSG_UIN,
1866 left -= sizeof(guint32);
1869 if (left>=(sizeof(guint16)+4*sizeof(unsigned char))) {
1870 year = pletohs(pd + SRV_RECV_MSG_YEAR);
1871 month = pd[SRV_RECV_MSG_MONTH];
1872 day = pd[SRV_RECV_MSG_DAY];
1873 hour = pd[SRV_RECV_MSG_HOUR];
1874 minute = pd[SRV_RECV_MSG_MINUTE];
1876 proto_tree_add_text(subtree,
1877 offset + SRV_RECV_MSG_YEAR,
1878 sizeof(guint16) + 4*sizeof(unsigned char),
1879 "Time: %u-%u-%u %02u:%02u",
1880 day, month, year, hour, minute);
1882 left -= (sizeof(guint16)+4*sizeof(unsigned char));
1885 icqv5_decode_msgType(subtree,
1886 pd + SRV_RECV_MSG_MSG_TYPE,
1887 offset + SRV_RECV_MSG_MSG_TYPE,
1893 icqv5_srv_rand_user(proto_tree* tree, /* Tree to put the data in */
1894 const u_char* pd, /* Packet content */
1895 int offset, /* Offset from the start of the packet to the content */
1896 int size) /* Number of chars left to do */
1898 proto_tree* subtree = NULL;
1899 proto_item* ti = NULL;
1901 const unsigned char* IP = NULL;
1903 const unsigned char* realIP = NULL;
1904 unsigned char commClass = -1;
1910 ti = proto_tree_add_uint_format(tree,
1913 SRV_RAND_USER_TCP_VER + 2,
1916 subtree = proto_item_add_subtree(ti, ett_icq_body);
1918 if (left<sizeof(guint32))
1920 uin = pletohl(pd + SRV_RAND_USER_UIN);
1921 proto_tree_add_text(subtree,
1922 offset + SRV_RAND_USER_UIN,
1925 left -= sizeof(guint32);
1927 if (left<sizeof(guint32))
1929 IP = pd + SRV_RAND_USER_IP;
1930 proto_tree_add_text(subtree,
1931 offset + SRV_RAND_USER_IP,
1933 "IP: %s", ip_to_str(IP));
1934 left -= sizeof(guint32);
1935 /* guint32 portNum */
1936 if (left<sizeof(guint32))
1938 port = pletohs(pd + SRV_RAND_USER_PORT);
1939 proto_tree_add_text(subtree,
1940 offset + SRV_RAND_USER_UIN,
1943 left -= sizeof(guint32);
1944 /* guint32 realIP */
1945 if (left<sizeof(guint32))
1947 realIP = pd + SRV_RAND_USER_REAL_IP;
1948 proto_tree_add_text(subtree,
1949 offset + SRV_RAND_USER_REAL_IP,
1951 "RealIP: %s", ip_to_str(realIP));
1952 left -= sizeof(guint32);
1953 /* guit16 Communication Class */
1954 if (left<sizeof(unsigned char))
1956 commClass = pd[SRV_RAND_USER_CLASS];
1957 proto_tree_add_text(subtree,
1958 offset + SRV_RAND_USER_CLASS,
1959 sizeof(unsigned char),
1960 "Class: %s", (commClass!=4)?"User to User":"Through Server");
1961 left -= sizeof(unsigned char);
1962 /* guint32 status */
1963 if (left<sizeof(guint32))
1965 status = pletohs(pd + SRV_RAND_USER_STATUS);
1966 proto_tree_add_text(subtree,
1967 offset + SRV_RAND_USER_STATUS,
1969 "Status: (%u) %s", status, findStatus(status));
1970 /* guint16 tcpVersion */
1971 if (left<sizeof(guint16))
1973 tcpVer = pletohs(pd + SRV_RAND_USER_TCP_VER);
1974 proto_tree_add_text(subtree,
1975 offset + SRV_RAND_USER_TCP_VER,
1977 "TCPVersion: %u", tcpVer);
1978 left -= sizeof(guint16);
1983 * Dissect all the v5 client traffic. This is encrypted, so be careful.
1986 dissect_icqv5Client(const u_char *pd,
1991 proto_tree *icq_tree = NULL;
1992 proto_tree *icq_header_tree = NULL;
1993 proto_tree *icq_decode_tree = NULL;
1994 proto_item *ti = NULL;
1996 guint16 version = -1, cmd = -1;
1997 guint16 seqnum1 = 0 , seqnum2 = 0;
1998 guint32 uin = -1, sessionid = -1;
2000 guint16 pktsize = -1; /* The size of the ICQ content */
2001 u_char decr_pd[1600]; /* Decrypted content, size should be dynamic */
2003 pktsize = END_OF_FRAME;
2004 /* First copy the memory, we don't want to overwrite the old content */
2005 memcpy(decr_pd, &pd[offset], pktsize);
2007 key = get_v5key(decr_pd, pktsize);
2008 decrypt_v5(decr_pd, pktsize, key);
2010 /* This information only makes sense in the decrypted version */
2011 uin = pletohl(&decr_pd[ICQ5_CL_UIN]);
2012 cmd = pletohs(&decr_pd[ICQ5_CL_CMD]);
2013 sessionid = pletohl(&decr_pd[ICQ5_CL_SESSIONID]);
2014 version = pletohs(&decr_pd[ICQ_VERSION]);
2015 seqnum1 = pletohs(&decr_pd[ICQ5_CL_SEQNUM1]);
2016 seqnum2 = pletohs(&decr_pd[ICQ5_CL_SEQNUM2]);
2018 if (check_col(fd, COL_INFO))
2019 col_add_fstr(fd, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
2023 ti = proto_tree_add_protocol_format(tree,
2027 "ICQv5 %s (len %u)",
2030 icq_tree = proto_item_add_subtree(ti, ett_icq);
2031 ti = proto_tree_add_uint_format(icq_tree,
2037 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
2039 proto_tree_add_uint_format(icq_header_tree,
2041 offset+ICQ5_CL_SESSIONID,
2044 "Session ID: 0x%08x",
2046 proto_tree_add_uint_format(icq_header_tree,
2048 offset+ICQ5_CL_CHECKCODE,
2053 proto_tree_add_uint_format(icq_header_tree,
2060 proto_tree_add_text(icq_header_tree,
2061 offset + ICQ5_CL_SEQNUM1,
2063 "Seqnum1: 0x%04x", seqnum1);
2064 proto_tree_add_text(icq_header_tree,
2065 offset + ICQ5_CL_SEQNUM1,
2067 "Seqnum2: 0x%04x", seqnum2);
2070 icqv5_cmd_ack(icq_tree,
2071 decr_pd + ICQ5_CL_HDRSIZE,
2072 offset + ICQ5_CL_HDRSIZE,
2073 pktsize - ICQ5_CL_HDRSIZE);
2076 case CMD_MSG_TO_NEW_USER:
2077 icqv5_cmd_send_msg(icq_tree,
2078 decr_pd + ICQ5_CL_HDRSIZE,
2079 offset + ICQ5_CL_HDRSIZE,
2080 pktsize - ICQ5_CL_HDRSIZE,
2083 case CMD_RAND_SEARCH:
2084 icqv5_cmd_rand_search(icq_tree,
2085 decr_pd + ICQ5_CL_HDRSIZE,
2086 offset + ICQ5_CL_HDRSIZE,
2087 pktsize - ICQ5_CL_HDRSIZE);
2090 icqv5_cmd_login(icq_tree,
2091 decr_pd + ICQ5_CL_HDRSIZE,
2092 offset + ICQ5_CL_HDRSIZE,
2093 pktsize - ICQ5_CL_HDRSIZE);
2095 case CMD_SEND_TEXT_CODE:
2096 icqv5_cmd_send_text_code(icq_tree,
2097 decr_pd + ICQ5_CL_HDRSIZE,
2098 offset + ICQ5_CL_HDRSIZE,
2099 pktsize - ICQ5_CL_HDRSIZE);
2101 case CMD_STATUS_CHANGE:
2102 icqv5_cmd_status_change(icq_tree,
2103 decr_pd + ICQ5_CL_HDRSIZE,
2104 offset + ICQ5_CL_HDRSIZE,
2105 pktsize - ICQ5_CL_HDRSIZE);
2107 case CMD_ACK_MESSAGES:
2108 icqv5_cmd_ack_messages(icq_tree,
2109 decr_pd + ICQ5_CL_HDRSIZE,
2110 offset + ICQ5_CL_HDRSIZE,
2111 pktsize - ICQ5_CL_HDRSIZE);
2113 case CMD_KEEP_ALIVE:
2114 icqv5_cmd_keep_alive(icq_tree,
2115 decr_pd + ICQ5_CL_HDRSIZE,
2116 offset + ICQ5_CL_HDRSIZE,
2117 pktsize - ICQ5_CL_HDRSIZE);
2119 case CMD_ADD_TO_LIST:
2120 icqv5_cmd_add_to_list(icq_tree,
2121 decr_pd + ICQ5_CL_HDRSIZE,
2122 offset + ICQ5_CL_HDRSIZE,
2123 pktsize - ICQ5_CL_HDRSIZE);
2125 case CMD_CONTACT_LIST:
2126 icqv5_cmd_contact_list(icq_tree,
2127 decr_pd + ICQ5_CL_HDRSIZE,
2128 offset + ICQ5_CL_HDRSIZE,
2129 pktsize - ICQ5_CL_HDRSIZE);
2132 case CMD_REG_NEW_USER:
2133 case CMD_QUERY_SERVERS:
2134 case CMD_QUERY_ADDONS:
2135 icqv5_cmd_no_params(icq_tree,
2136 decr_pd + ICQ5_CL_HDRSIZE,
2137 offset + ICQ5_CL_HDRSIZE,
2138 pktsize - ICQ5_CL_HDRSIZE,
2142 proto_tree_add_uint_format(icq_tree,
2148 cmd, findClientCmd(cmd));
2149 fprintf(stderr,"Missing: %s\n", findClientCmd(cmd));
2152 ti = proto_tree_add_text(icq_tree,
2156 icq_decode_tree = proto_item_add_subtree(ti,
2158 proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
2164 dissect_icqv5Server(const u_char *pd,
2170 /* Server traffic is easy, not encrypted */
2171 proto_tree *icq_tree = NULL;
2172 proto_tree *icq_header_tree = NULL;
2173 proto_tree *icq_decode_tree = NULL;
2174 proto_item *ti = NULL;
2175 const u_char* decr_pd;
2176 int changeCol = (pktsize==(guint32)-1);
2178 guint16 version, cmd;
2179 guint32 uin, sessionid;
2180 guint16 seq_num1, seq_num2;
2183 uin = pletohl(&pd[ICQ5_SRV_UIN]);
2184 sessionid = pletohl(&pd[ICQ5_SRV_SESSIONID]);
2185 cmd = pletohs(&pd[ICQ5_SRV_CMD]);
2186 version = pletohs(&pd[ICQ_VERSION]);
2187 checkcode = pletohl(&pd[ICQ5_SRV_CHECKCODE]);
2188 seq_num1 = pletohs(&pd[ICQ5_SRV_SEQNUM1]);
2189 seq_num2 = pletohs(&pd[ICQ5_SRV_SEQNUM2]);
2191 pktsize = fd->pkt_len - offset;
2194 if (changeCol && check_col(fd, COL_INFO))
2195 col_add_fstr(fd, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
2198 ti = proto_tree_add_protocol_format(tree,
2202 "ICQv5 %s (len %u)",
2206 icq_tree = proto_item_add_subtree(ti, ett_icq);
2208 ti = proto_tree_add_uint_format(icq_tree,
2214 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
2216 proto_tree_add_uint_format(icq_header_tree,
2218 offset+ICQ5_SRV_SESSIONID,
2221 "Session ID: 0x%08x",
2223 proto_tree_add_text(icq_header_tree,
2224 offset+ICQ5_SRV_SEQNUM1,
2226 "Seq Number1: 0x%04x",
2228 proto_tree_add_text(icq_header_tree,
2229 offset+ICQ5_SRV_SEQNUM2,
2231 "Seq Number2: 0x%04x",
2233 proto_tree_add_uint_format(icq_header_tree,
2235 offset+ICQ5_SRV_UIN,
2240 proto_tree_add_uint_format(icq_header_tree,
2242 offset+ICQ5_SRV_CHECKCODE,
2245 "Checkcode: 0x%08x",
2249 icqv5_srv_rand_user(icq_tree,
2250 decr_pd + ICQ5_SRV_HDRSIZE,
2251 offset + ICQ5_SRV_HDRSIZE,
2252 pktsize - ICQ5_SRV_HDRSIZE);
2254 case SRV_SYS_DELIVERED_MESS:
2255 /* The message structures are all the same. Why not run
2256 * the same routine? */
2257 icqv5_cmd_send_msg(icq_tree,
2258 decr_pd + ICQ5_SRV_HDRSIZE,
2259 offset + ICQ5_SRV_HDRSIZE,
2260 pktsize - ICQ5_SRV_HDRSIZE,
2263 case SRV_USER_ONLINE:
2264 icqv5_srv_user_online(icq_tree,
2265 decr_pd + ICQ5_SRV_HDRSIZE,
2266 offset + ICQ5_SRV_HDRSIZE,
2267 pktsize - ICQ5_SRV_HDRSIZE);
2269 case SRV_USER_OFFLINE:
2270 icqv5_srv_user_offline(icq_tree,
2271 decr_pd + ICQ5_SRV_HDRSIZE,
2272 offset + ICQ5_SRV_HDRSIZE,
2273 pktsize - ICQ5_SRV_HDRSIZE);
2275 case SRV_LOGIN_REPLY:
2276 icqv5_srv_login_reply(icq_tree,
2277 decr_pd + ICQ5_SRV_HDRSIZE,
2278 offset + ICQ5_SRV_HDRSIZE,
2279 pktsize - ICQ5_SRV_HDRSIZE);
2282 icqv5_srv_meta_user(icq_tree,
2283 decr_pd + ICQ5_SRV_HDRSIZE,
2284 offset + ICQ5_SRV_HDRSIZE,
2285 pktsize - ICQ5_SRV_HDRSIZE);
2287 case SRV_RECV_MESSAGE:
2288 icqv5_srv_recv_message(icq_tree,
2289 decr_pd + ICQ5_SRV_HDRSIZE,
2290 offset + ICQ5_SRV_HDRSIZE,
2291 pktsize - ICQ5_SRV_HDRSIZE);
2294 icqv5_srv_multi(icq_tree,
2295 decr_pd + ICQ5_SRV_HDRSIZE,
2296 offset + ICQ5_SRV_HDRSIZE,
2297 pktsize - ICQ5_SRV_HDRSIZE,
2304 case SRV_UPDATE_SUCCESS:
2305 icqv5_srv_no_params(icq_tree,
2306 decr_pd + ICQ5_SRV_HDRSIZE,
2307 offset + ICQ5_SRV_HDRSIZE,
2308 pktsize - ICQ5_SRV_HDRSIZE,
2312 proto_tree_add_uint_format(icq_tree,
2314 offset + ICQ5_SRV_CMD,
2318 cmd, findServerCmd(cmd));
2319 fprintf(stderr,"Missing: %s\n", findServerCmd(cmd));
2323 ti = proto_tree_add_text(icq_tree,
2327 icq_decode_tree = proto_item_add_subtree(ti,
2329 proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
2333 void dissect_icqv5(const u_char *pd,
2338 guint32 unknown = pletohl(&pd[offset + ICQ5_UNKNOWN]);
2340 if (check_col(fd, COL_PROTOCOL))
2341 col_add_str(fd, COL_PROTOCOL, "ICQv5 (UDP)");
2342 if (check_col(fd, COL_INFO))
2343 col_add_str(fd, COL_INFO, "ICQv5 packet");
2344 if (unknown == 0x0L) {
2345 dissect_icqv5Client(pd, offset, fd, tree);
2347 dissect_icqv5Server(pd + offset, offset, fd, tree, (guint32) -1);
2351 void dissect_icq(const u_char *pd,
2358 version = pletohs(&pd[offset + ICQ_VERSION]);
2361 dissect_icqv5(pd, offset, fd, tree);
2364 dissect_icqv2(pd, offset, fd, tree);
2367 fprintf(stderr, "ICQ: Unknown version (%d)\n", version);
2372 /* registration with the filtering engine */
2374 proto_register_icq(void)
2376 static hf_register_info hf[] = {
2378 {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2380 {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, ""}},
2381 { &hf_icq_sessionid,
2382 {"SessionID", "icq.sessionid", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2384 {"Command", "icq.cmd", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2385 { &hf_icq_checkcode,
2386 {"Checkcode", "icq.checkcode", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2388 {"Decode", "icq.decode", FT_STRING, BASE_NONE, NULL, 0x0, ""}}
2390 static gint *ett[] = {
2395 &ett_icq_body_parts,
2398 proto_icq = proto_register_protocol ("ICQ Protocol", "icq");
2400 proto_register_field_array(proto_icq, hf, array_length(hf));
2402 proto_register_subtree_array(ett, array_length(ett));