2 * Routines for ICQ packet disassembly
4 * $Id: packet-icq.c,v 1.15 2000/05/11 08:15:10 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 #define UDP_PORT_ICQ 4000
87 enum { ICQ5_client, ICQ5_server};
89 static void dissect_icqv5(const u_char *pd,
95 dissect_icqv5Server(const u_char *pd,
101 /* Offsets of fields in the ICQ headers */
102 /* Can be 0x0002 or 0x0005 */
103 #define ICQ_VERSION 0x00
104 /* Is either one (server) or four (client) bytes long */
105 /* Client header offsets */
106 #define ICQ5_UNKNOWN 0x02
107 #define ICQ5_CL_UIN 0x06
108 #define ICQ5_CL_SESSIONID 0x0a
109 #define ICQ5_CL_CMD 0x0e
110 #define ICQ5_CL_SEQNUM1 0x10
111 #define ICQ5_CL_SEQNUM2 0x12
112 #define ICQ5_CL_CHECKCODE 0x14
113 #define ICQ5_CL_PARAM 0x18
114 #define ICQ5_CL_HDRSIZE 0x18
116 /* Server header offsets */
117 #define ICQ5_SRV_SESSIONID 0x03
118 #define ICQ5_SRV_CMD 0x07
119 #define ICQ5_SRV_SEQNUM1 0x09
120 #define ICQ5_SRV_SEQNUM2 0x0b
121 #define ICQ5_SRV_UIN 0x0d
122 #define ICQ5_SRV_CHECKCODE 0x11
123 #define ICQ5_SRV_PARAM 0x15
124 #define ICQ5_SRV_HDRSIZE 0x15
126 typedef struct _cmdcode {
131 #define SRV_ACK 0x000a
133 #define SRV_GO_AWAY 0x0028
135 #define SRV_NEW_UIN 0x0046
137 /* LOGIN_REPLY is very scary. It has a lot of fields that are undocumented
138 * Only the IP field makes sense */
139 #define SRV_LOGIN_REPLY 0x005a
140 #define SRV_LOGIN_REPLY_IP 0x000c
142 #define SRV_BAD_PASS 0x0064
144 #define SRV_USER_ONLINE 0x006e
145 #define SRV_USER_ONL_UIN 0x0000
146 #define SRV_USER_ONL_IP 0x0004
147 #define SRV_USER_ONL_PORT 0x0008
148 #define SRV_USER_ONL_REALIP 0x000c
149 #define SRV_USER_ONL_X1 0x0010
150 #define SRV_USER_ONL_STATUS 0x0013
151 #define SRV_USER_ONL_X2 0x0015
153 #define SRV_USER_OFFLINE 0x0078
154 #define SRV_USER_OFFLINE_UIN 0x0000
156 #define SRV_MULTI 0x0212
157 #define SRV_MULTI_NUM 0x0000
159 #define SRV_META_USER 0x03de
160 #define SRV_META_USER_SUBCMD 0x0000
161 #define SRV_META_USER_RESULT 0x0002
162 #define SRV_META_USER_DATA 0x0003
164 #define SRV_UPDATE_SUCCESS 0x01e0
166 #define SRV_UPDATE_FAIL 0x01ea
169 * ICQv5 SRV_META_USER subcommands
171 #define META_EX_USER_FOUND 0x0190
172 #define META_USER_FOUND 0x019a
173 #define META_ABOUT 0x00e6
174 #define META_USER_INFO 0x00c8
176 #define SRV_RECV_MESSAGE 0x00dc
177 #define SRV_RECV_MSG_UIN 0x0000
178 #define SRV_RECV_MSG_YEAR 0x0004
179 #define SRV_RECV_MSG_MONTH 0x0006
180 #define SRV_RECV_MSG_DAY 0x0007
181 #define SRV_RECV_MSG_HOUR 0x0008
182 #define SRV_RECV_MSG_MINUTE 0x0009
183 #define SRV_RECV_MSG_MSG_TYPE 0x000a
185 #define SRV_RAND_USER 0x024e
186 #define SRV_RAND_USER_UIN 0x0000
187 #define SRV_RAND_USER_IP 0x0004
188 #define SRV_RAND_USER_PORT 0x0008
189 #define SRV_RAND_USER_REAL_IP 0x000c
190 #define SRV_RAND_USER_CLASS 0x0010
191 #define SRV_RAND_USER_X1 0x0011
192 #define SRV_RAND_USER_STATUS 0x0015
193 #define SRV_RAND_USER_TCP_VER 0x0019
195 /* This message has the same structure as cmd_send_msg */
196 #define SRV_SYS_DELIVERED_MESS 0x0104
198 cmdcode serverMetaSubCmdCode[] = {
199 { "META_USER_FOUND", META_USER_FOUND },
200 { "META_EX_USER_FOUND", META_EX_USER_FOUND },
201 { "META_ABOUT", META_ABOUT },
202 { "META_USER_INFO", META_USER_INFO },
206 cmdcode serverCmdCode[] = {
207 { "SRV_ACK", SRV_ACK },
208 { "SRV_GO_AWAY", SRV_GO_AWAY },
209 { "SRV_NEW_UIN", SRV_NEW_UIN },
210 { "SRV_LOGIN_REPLY", SRV_LOGIN_REPLY },
211 { "SRV_BAD_PASS", SRV_BAD_PASS },
212 { "SRV_USER_ONLINE", SRV_USER_ONLINE },
213 { "SRV_USER_OFFLINE", SRV_USER_OFFLINE },
214 { "SRV_QUERY", 130 },
215 { "SRV_USER_FOUND", 140 },
216 { "SRV_END_OF_SEARCH", 160 },
217 { "SRV_NEW_USER", 180 },
218 { "SRV_UPDATE_EXT", 200 },
219 { "SRV_RECV_MESSAGE", SRV_RECV_MESSAGE },
221 { "SRV_NOT_CONNECTED", 240 },
222 { "SRV_TRY_AGAIN", 250 },
223 { "SRV_SYS_DELIVERED_MESS", SRV_SYS_DELIVERED_MESS },
224 { "SRV_INFO_REPLY", 280 },
225 { "SRV_EXT_INFO_REPLY", 290 },
226 { "SRV_STATUS_UPDATE", 420 },
227 { "SRV_SYSTEM_MESSAGE", 450 },
228 { "SRV_UPDATE_SUCCESS", SRV_UPDATE_SUCCESS },
229 { "SRV_UPDATE_FAIL", SRV_UPDATE_FAIL },
230 { "SRV_AUTH_UPDATE", 500 },
231 { "SRV_MULTI_PACKET", SRV_MULTI },
233 { "SRV_RAND_USER", SRV_RAND_USER },
234 { "SRV_META_USER", SRV_META_USER },
238 #define MSG_TEXT 0x0001
239 #define MSG_URL 0x0004
240 #define MSG_AUTH_REQ 0x0006
241 #define MSG_AUTH 0x0008
242 #define MSG_USER_ADDED 0x000c
243 #define MSG_EMAIL 0x000e
244 #define MSG_CONTACTS 0x0013
246 #define STATUS_ONLINE 0x00000000
247 #define STATUS_AWAY 0x00000001
248 #define STATUS_DND 0x00000013
249 #define STATUS_INVISIBLE 0x00000100
250 #define STATUS_OCCUPIED 0x00000010
251 #define STATUS_NA 0x00000004
252 #define STATUS_CHAT 0x00000020
254 /* Offsets for all packets measured from the start of the payload; i.e.
255 * with the ICQ header removed
257 #define CMD_ACK 0x000a
258 #define CMD_ACK_RANDOM 0x0000
260 #define CMD_SEND_MSG 0x010E
261 #define CMD_SEND_MSG_RECV_UIN 0x0000
262 #define CMD_SEND_MSG_MSG_TYPE 0x0004
263 #define CMD_SEND_MSG_MSG_LEN 0x0006
264 #define CMD_SEND_MSG_MSG_TEXT 0x0008
265 /* The rest of the packet should be a null-term string */
267 #define CMD_LOGIN 0x03E8
268 #define CMD_LOGIN_TIME 0x0000
269 #define CMD_LOGIN_PORT 0x0004
270 #define CMD_LOGIN_PASSLEN 0x0008
271 #define CMD_LOGIN_PASSWD 0x000A
272 /* The password is variable length; so when we've decoded the passwd,
273 * the structure starts counting at 0 again.
275 #define CMD_LOGIN_IP 0x0004
276 #define CMD_LOGIN_STATUS 0x0009
278 #define CMD_CONTACT_LIST 0x0406
279 #define CMD_CONTACT_LIST_NUM 0x0000
281 #define CMD_USER_META 0x064a
283 #define CMD_REG_NEW_USER 0x03fc
285 #define CMD_ACK_MESSAGES 0x0442
286 #define CMD_ACK_MESSAGES_RANDOM 0x0000
288 #define CMD_KEEP_ALIVE 0x042e
289 #define CMD_KEEP_ALIVE_RANDOM 0x0000
291 #define CMD_SEND_TEXT_CODE 0x0438
292 #define CMD_SEND_TEXT_CODE_LEN 0x0000
293 #define CMD_SEND_TEXT_CODE_TEXT 0x0002
295 #define CMD_MSG_TO_NEW_USER 0x0456
297 #define CMD_QUERY_SERVERS 0x04ba
299 #define CMD_QUERY_ADDONS 0x04c4
301 #define CMD_STATUS_CHANGE 0x04d8
302 #define CMD_STATUS_CHANGE_STATUS 0x0000
304 #define CMD_ADD_TO_LIST 0x053c
305 #define CMD_ADD_TO_LIST_UIN 0x0000
307 #define CMD_RAND_SEARCH 0x056e
308 #define CMD_RAND_SEARCH_GROUP 0x0000
310 #define CMD_META_USER 0x064a
312 cmdcode msgTypeCode[] = {
313 { "MSG_TEXT", MSG_TEXT },
314 { "MSG_URL", MSG_URL },
315 { "MSG_AUTH_REQ", MSG_AUTH_REQ },
316 { "MSG_AUTH", MSG_AUTH },
317 { "MSG_USER_ADDED", MSG_USER_ADDED},
318 { "MSG_EMAIL", MSG_EMAIL},
319 { "MSG_CONTACTS", MSG_CONTACTS},
323 cmdcode statusCode[] = {
324 { "ONLINE", STATUS_ONLINE },
325 { "AWAY", STATUS_AWAY },
326 { "DND", STATUS_DND },
327 { "INVISIBLE", STATUS_INVISIBLE },
328 { "OCCUPIED", STATUS_OCCUPIED },
330 { "Free for Chat", STATUS_CHAT },
334 cmdcode clientCmdCode[] = {
335 { "CMD_ACK", CMD_ACK },
336 { "CMD_SEND_MESSAGE", CMD_SEND_MSG },
337 { "CMD_LOGIN", CMD_LOGIN },
338 { "CMD_REG_NEW_USER", CMD_REG_NEW_USER },
339 { "CMD_CONTACT_LIST", 1030 },
340 { "CMD_SEARCH_UIN", 1050 },
341 { "CMD_SEARCH_USER", 1060 },
342 { "CMD_KEEP_ALIVE", 1070 },
343 { "CMD_SEND_TEXT_CODE", CMD_SEND_TEXT_CODE },
344 { "CMD_ACK_MESSAGES", CMD_ACK_MESSAGES },
345 { "CMD_LOGIN_1", 1100 },
346 { "CMD_MSG_TO_NEW_USER", CMD_MSG_TO_NEW_USER },
347 { "CMD_INFO_REQ", 1120 },
348 { "CMD_EXT_INFO_REQ", 1130 },
349 { "CMD_CHANGE_PW", 1180 },
350 { "CMD_NEW_USER_INFO", 1190 },
351 { "CMD_UPDATE_EXT_INFO", 1200 },
352 { "CMD_QUERY_SERVERS", CMD_QUERY_SERVERS },
353 { "CMD_QUERY_ADDONS", CMD_QUERY_ADDONS },
354 { "CMD_STATUS_CHANGE", CMD_STATUS_CHANGE },
355 { "CMD_NEW_USER_1", 1260 },
356 { "CMD_UPDATE_INFO", 1290 },
357 { "CMD_AUTH_UPDATE", 1300 },
358 { "CMD_KEEP_ALIVE2", 1310 },
359 { "CMD_LOGIN_2", 1320 },
360 { "CMD_ADD_TO_LIST", CMD_ADD_TO_LIST },
361 { "CMD_RAND_SET", 1380 },
362 { "CMD_RAND_SEARCH", CMD_RAND_SEARCH },
363 { "CMD_META_USER", CMD_META_USER },
364 { "CMD_INVIS_LIST", 1700 },
365 { "CMD_VIS_LIST", 1710 },
366 { "CMD_UPDATE_LIST", 1720 },
371 * All ICQv5 decryption code thanx to Sebastien Dault (daus01@gel.usherb.ca)
375 0x59, 0x60, 0x37, 0x6B, 0x65, 0x62, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x60, 0x57, 0x5B, 0x3D,
376 0x5E, 0x34, 0x6D, 0x36, 0x50, 0x3F, 0x6F, 0x67, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x47, 0x63, 0x39,
377 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x43, 0x69, 0x48, 0x33, 0x31, 0x64, 0x35, 0x5A, 0x4A, 0x42,
378 0x56, 0x40, 0x67, 0x53, 0x41, 0x07, 0x6C, 0x49, 0x58, 0x3B, 0x4D, 0x46, 0x68, 0x43, 0x69, 0x48,
379 0x33, 0x31, 0x44, 0x65, 0x62, 0x46, 0x48, 0x53, 0x41, 0x07, 0x6C, 0x69, 0x48, 0x33, 0x51, 0x54,
380 0x5D, 0x4E, 0x6C, 0x49, 0x38, 0x4B, 0x55, 0x4A, 0x62, 0x46, 0x48, 0x33, 0x51, 0x34, 0x6D, 0x36,
381 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x63, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64, 0x35, 0x5A,
382 0x6A, 0x52, 0x6E, 0x3C, 0x51, 0x34, 0x6D, 0x36, 0x50, 0x5F, 0x5F, 0x3F, 0x4F, 0x37, 0x4B, 0x35,
383 0x5A, 0x4A, 0x62, 0x66, 0x58, 0x3B, 0x4D, 0x66, 0x58, 0x5B, 0x5D, 0x4E, 0x6C, 0x49, 0x58, 0x3B,
384 0x4D, 0x66, 0x58, 0x3B, 0x4D, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64,
385 0x55, 0x6A, 0x32, 0x3E, 0x44, 0x45, 0x52, 0x6E, 0x3C, 0x31, 0x64, 0x55, 0x6A, 0x52, 0x4E, 0x6C,
386 0x69, 0x48, 0x53, 0x61, 0x4C, 0x39, 0x30, 0x6F, 0x47, 0x63, 0x59, 0x60, 0x57, 0x5B, 0x3D, 0x3E,
387 0x64, 0x35, 0x3A, 0x3A, 0x5A, 0x6A, 0x52, 0x4E, 0x6C, 0x69, 0x48, 0x53, 0x61, 0x6C, 0x49, 0x58,
388 0x3B, 0x4D, 0x46, 0x68, 0x63, 0x39, 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x67, 0x53, 0x41, 0x25, 0x41,
389 0x3C, 0x51, 0x54, 0x3D, 0x5E, 0x54, 0x5D, 0x4E, 0x4C, 0x39, 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F,
390 0x47, 0x43, 0x69, 0x48, 0x33, 0x51, 0x54, 0x5D, 0x6E, 0x3C, 0x31, 0x64, 0x35, 0x5A, 0x00, 0x00 };
393 findcmd(cmdcode* c, int num)
397 while (p->descr != NULL) {
398 if (p->code == num) {
403 snprintf(buf, sizeof(buf), "(%x)", num);
410 return findcmd(msgTypeCode, num);
416 return findcmd(serverMetaSubCmdCode, num);
420 findClientCmd(int num)
422 return findcmd(clientCmdCode, num);
426 findServerCmd(int num)
428 return findcmd(serverCmdCode, num);
434 return findcmd(statusCode, num);
438 proto_tree_add_hexdump(proto_tree* t,
446 int done = 0, line = 0;
454 for (i=0;i<line;i++) {
457 for (n = i * 16; n < (i+1)*16; n++) {
458 added = sprintf(buf+done, "%02x", data[n]);
460 added += sprintf(buf + done + added, " ");
462 added += sprintf(buf + done + added, " ");
465 for (n = i * 16; n < (i+1)*16; n++) {
466 if (isprint(data[n]))
467 added = sprintf(buf + done, "%c", data[n]);
469 added = sprintf(buf + done, ".");
472 proto_tree_add_text(t, NullTVB,
479 for (n = line * 16 ; n < size ; n++) {
480 added = sprintf(buf+done, "%02x", data[n]);
482 added += sprintf(buf + done + added, " ");
484 added += sprintf(buf + done + added, " ");
487 for (n = size ; (n%16)!=0;n++) {
490 added += sprintf(buf + done + added, " ");
492 added += sprintf(buf + done + added, " ");
495 for (n = line * 16; n < (line+1)*16; n++) {
498 if (isprint(data[n]))
499 added = sprintf(buf + done, "%c", data[n]);
501 added = sprintf(buf + done, ".");
503 added = sprintf(buf + done, " ");
507 proto_tree_add_text(t, NullTVB,
515 get_v5key(const u_char* pd, int len)
517 guint32 a1, a2, a3, a4, a5;
518 guint32 code, check, key;
520 code = pletohl(&pd[ICQ5_CL_CHECKCODE]);
522 a1 = code & 0x0001f000;
523 a2 = code & 0x07c007c0;
524 a3 = code & 0x003e0001;
525 a4 = code & 0xf8000000;
526 a5 = code & 0x0000083e;
534 check = a5 + a1 + a2 + a3 + a4;
535 key = len * 0x68656C6C;
541 decrypt_v5(u_char *bfr, guint32 size,guint32 key)
545 for (i=0x0a; i < size+3; i+=4 ) {
546 k = key+table_v5[i&0xff];
548 bfr[i] ^= (u_char)(k & 0xff);
549 bfr[i+1] ^= (u_char)((k & 0xff00)>>8);
552 bfr[i+2] ^= (u_char)((k & 0xff0000)>>16);
553 bfr[i+3] ^= (u_char)((k & 0xff000000)>>24);
559 dissect_icqv2(const u_char *pd,
564 /* Not really implemented yet */
565 if (check_col(fd, COL_PROTOCOL)) {
566 col_add_str(fd, COL_PROTOCOL, "ICQv2 (UDP)");
568 if (check_col(fd, COL_INFO)) {
569 col_add_str(fd, COL_INFO, "ICQ Version 2 protocol");
574 * Find first occurrence of ch in buf
575 * Buf is max size big.
578 strnchr(const u_char* buf, u_char ch, int size)
581 u_char* p = (u_char*) buf;
582 for (i=0;(*p) && (*p!=ch) && (i<size); p++, i++)
584 if ((*p == '\0') || (i>=size))
590 * The packet at pd has a (len, string) pair.
591 * Copy the string to a buffer, and display it in the tree.
592 * Observe any limits you might cross.
594 * If anything is wrong, return -1, since -1 is not a valid string
595 * length. Else, return the number of chars processed.
598 proto_add_icq_attr(proto_tree* tree, /* The tree to add to */
599 const char* pd, /* Pointer to the field */
600 const int offset, /* Offset from the start of packet */
601 const int size, /* The number of bytes left in pd */
602 char* descr) /* The description to use in the tree */
608 if (size<sizeof(guint16))
611 left -= sizeof(guint16);
613 proto_tree_add_text(tree, NullTVB,
620 data = g_malloc(len);
622 strncpy(data, pd + sizeof(guint16), len);
623 data[len - 1] = '\0';
625 proto_tree_add_text(tree, NullTVB,
627 sizeof(guint16) + len,
628 "%s[%u]: %s", descr, len, data);
631 return len + sizeof(guint16);
635 icqv5_decode_msgType(proto_tree* tree,
636 const unsigned char* pd, /* From start of messageType */
640 proto_item* ti = NULL;
641 proto_tree* subtree = NULL;
643 char *msgText = NULL;
644 guint16 msgType = -1;
647 static char* auth_req_field_descr[] = {
654 static char* emain_field_descr[] = {
663 enum {OFF_MSG_TYPE=0,
668 if (left >= sizeof(guint16)) {
669 msgType = pletohs(pd + OFF_MSG_TYPE);
670 left -= sizeof(guint16);
672 if (left >= sizeof(guint16)) {
673 msgLen = pletohs(pd + OFF_MSG_LEN);
674 left -= sizeof(guint16);
677 ti = proto_tree_add_text(tree, NullTVB,
680 "Type: %u (%s)", msgType, findMsgType(msgType));
681 /* Create a new subtree */
682 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
685 case 0xffff: /* Field unknown */
688 fprintf(stderr, "Unknown msgType: %u (%04x)\n", msgType, msgType);
691 msgText = g_malloc(left + 1);
692 strncpy(msgText, pd + OFF_MSG_TEXT, left);
693 msgText[left] = '\0';
694 proto_tree_add_text(subtree, NullTVB,
695 offset + OFF_MSG_TEXT,
701 /* Two parts, a description and the URL. Separeted by FE */
702 for (i=0;i<left;i++) {
703 if (pd[OFF_MSG_TEXT + i] == 0xfe)
706 msgText = g_malloc(i + 1);
707 strncpy(msgText, pd + OFF_MSG_TEXT, i);
712 proto_tree_add_text(subtree, NullTVB,
713 offset + OFF_MSG_TEXT,
715 "Description: %s", msgText);
718 msgText = g_realloc(msgText, left - i);
719 strncpy(msgText, pd + OFF_MSG_TEXT + i + 1, left - i - 1);
720 msgText[left - i] = '\0';
721 proto_tree_add_text(subtree, NullTVB,
722 offset + OFF_MSG_TEXT,
731 for (n = 0; n < 6; n++) {
733 (i<left) && (pd[OFF_MSG_TEXT+i]!=0xfe);
737 msgText = g_realloc(msgText, i-j);
738 strncpy(msgText, pd + OFF_MSG_TEXT + j, i - j - 1);
739 msgText[i-j-1] = '\0';
740 proto_tree_add_text(subtree, NullTVB,
741 offset + OFF_MSG_TEXT + j,
743 "%s: %s", emain_field_descr[n], msgText);
745 proto_tree_add_text(subtree, NullTVB,
746 offset + OFF_MSG_TEXT + j,
748 "%s: %s", emain_field_descr[n], "(empty)");
758 /* Three bytes, first is a char signifying success */
759 unsigned char auth_suc = pd[OFF_MSG_LEN];
760 guint16 x1 = pd[OFF_MSG_LEN+1];
761 proto_tree_add_text(subtree, NullTVB,
762 offset + OFF_MSG_LEN,
764 "Authorization: (%u) %s",auth_suc,
765 (auth_suc==0)?"Denied":"Allowed");
766 proto_tree_add_text(subtree, NullTVB,
767 offset + OFF_MSG_LEN + 1,
773 /* Six parts, separated by FE */
776 msgText = g_malloc(64);
777 for (n = 0; n < 6 && i<left; n++) {
778 while (i<left && pd[OFF_MSG_TEXT+i]!=0xfe)
781 /* pd[OFF_MSG_TEXT+i] == 0xfe */
783 /* Otherwise, it'd be a null string */
784 msgText = g_realloc(msgText, i - j);
785 strncpy(msgText, pd + OFF_MSG_TEXT + j, i-j);
787 proto_tree_add_text(subtree, NullTVB,
788 offset + OFF_MSG_TEXT + j,
790 "%s: %s", auth_req_field_descr[n], msgText);
792 proto_tree_add_text(subtree, NullTVB,
793 offset + OFF_MSG_TEXT + j,
795 "%s: %s", auth_req_field_descr[n], "(null)");
798 /* i and j point after the 0xfe character */
806 /* Four parts, separated by FE */
809 /* This is necessary, because g_realloc does not behave like
810 * g_malloc if the first parameter == NULL */
811 msgText = g_malloc(64);
812 for (n = 0; n < 4 && i<left; n++) {
813 while (i<left && pd[OFF_MSG_TEXT+i]!=0xfe)
816 /* pd[OFF_MSG_TEXT+i] == 0xfe */
818 /* Otherwise, it'd be a null string */
819 msgText = g_realloc(msgText, i - j);
820 strncpy(msgText, pd + OFF_MSG_TEXT + j, i-j);
822 proto_tree_add_text(subtree, NullTVB,
823 offset + OFF_MSG_TEXT + j,
825 "%s: %s", auth_req_field_descr[n], msgText);
827 proto_tree_add_text(subtree, NullTVB,
828 offset + OFF_MSG_TEXT + j,
830 "%s: %s", auth_req_field_descr[n], "(null)");
833 /* i and j point after the 0xfe character */
841 u_char* p = (u_char*) &pd[OFF_MSG_TEXT];
843 int sz = 0; /* Size of the current element */
844 int n = 0; /* The nth element */
845 int done = 0; /* Number of chars processed */
846 u_char* msgText2 = NULL;
848 /* Create a new subtree */
849 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
851 p = strnchr(pprev, 0xfe, left);
854 sz = (int)(p - pprev);
857 msgText = g_realloc(msgText, sz+1);
858 strncpy(msgText, pprev, sz);
862 /* The first element is the number of Nick/UIN pairs follow */
863 proto_tree_add_text(subtree, NullTVB,
864 offset + OFF_MSG_TEXT + done,
866 "Number of pairs: %s", msgText);
868 } else if (p!=NULL) {
872 p = strnchr(pprev, 0xfe, left);
874 sz = (int)(p - pprev);
877 msgText2 = g_malloc(sz+1);
878 strncpy(msgText2, pprev, sz);
881 proto_tree_add_text(subtree, NullTVB,
882 offset + OFF_MSG_TEXT + done,
884 "%s:%s", msgText, msgText2);
898 /*********************************
902 *********************************/
904 icqv5_cmd_ack(proto_tree* tree,/* Tree to put the data in */
905 const u_char* pd, /* Packet content */
906 int offset, /* Offset from the start of the packet to the content */
907 int size) /* Number of chars left to do */
909 guint32 random = pletohl(pd + CMD_ACK_RANDOM);
914 ti = proto_tree_add_uint_format(tree,
921 subtree = proto_item_add_subtree(ti, ett_icq_body);
922 proto_tree_add_text(subtree, NullTVB,
923 offset + CMD_ACK_RANDOM,
925 "Random: 0x%08x", random);
930 icqv5_cmd_rand_search(proto_tree* tree, /* Tree to put the data in */
931 const u_char* pd, /* Packet content */
932 int offset, /* Offset from the start of the packet to the content */
933 int size) /* Number of chars left to do */
935 guint16 group = pletohs(pd + CMD_RAND_SEARCH_GROUP);
939 static const char* groups[] = {
954 ti = proto_tree_add_uint_format(tree,
961 subtree = proto_item_add_subtree(ti, ett_icq_body);
962 if (group>0 && (group<=sizeof(groups)/sizeof(const char*)))
963 proto_tree_add_text(subtree, NullTVB,
964 offset + CMD_RAND_SEARCH_GROUP,
966 "Group: (%u) %s", group, groups[group-1]);
968 proto_tree_add_text(subtree, NullTVB,
969 offset + CMD_RAND_SEARCH_GROUP,
971 "Group: (%u)", group);
976 icqv5_cmd_ack_messages(proto_tree* tree,/* Tree to put the data in */
977 const u_char* pd, /* Packet content */
978 int offset, /* Offset from the start of the packet to the content */
979 int size) /* Number of chars left to do */
981 guint32 random = pletohl(pd + CMD_ACK_MESSAGES_RANDOM);
986 ti = proto_tree_add_uint_format(tree,
993 subtree = proto_item_add_subtree(ti, ett_icq_body);
994 proto_tree_add_text(subtree, NullTVB,
995 offset + CMD_ACK_MESSAGES_RANDOM,
997 "Random: 0x%08x", random);
1002 icqv5_cmd_keep_alive(proto_tree* tree,/* Tree to put the data in */
1003 const u_char* pd, /* Packet content */
1004 int offset, /* Offset from the start of the packet to the content */
1005 int size) /* Number of chars left to do */
1007 guint32 random = pletohl(pd + CMD_KEEP_ALIVE_RANDOM);
1008 proto_tree* subtree;
1012 ti = proto_tree_add_uint_format(tree,
1019 subtree = proto_item_add_subtree(ti, ett_icq_body);
1020 proto_tree_add_text(subtree, NullTVB,
1021 offset + CMD_KEEP_ALIVE_RANDOM,
1023 "Random: 0x%08x", random);
1028 icqv5_cmd_send_text_code(proto_tree* tree,/* Tree to put the data in */
1029 const u_char* pd, /* Packet content */
1030 int offset, /* Offset from the start of the packet to the content */
1031 int size) /* Number of chars left to do */
1033 proto_tree* subtree = NULL;
1034 proto_item* ti = NULL;
1038 int left = size; /* The amount of data left to analyse */
1041 ti = proto_tree_add_uint_format(tree,
1050 if (left<sizeof(guint16))
1052 len = pletohs(pd+CMD_SEND_TEXT_CODE_LEN);
1053 left -= sizeof(gint16);
1055 subtree = proto_item_add_subtree(ti, ett_icq_body);
1056 proto_tree_add_text(subtree, NullTVB,
1057 offset + CMD_SEND_TEXT_CODE_LEN,
1063 len = MIN(len, left);
1064 text = g_malloc(len+1);
1065 memcpy(text, pd + CMD_SEND_TEXT_CODE_TEXT, len);
1069 proto_tree_add_text(subtree, NullTVB,
1070 offset + CMD_SEND_TEXT_CODE_TEXT,
1077 if (left<sizeof(gint16))
1080 x1 = pletohs(pd + size - left);
1081 left -= sizeof(gint16);
1083 proto_tree_add_text(subtree, NullTVB,
1084 offset + CMD_SEND_TEXT_CODE_TEXT + len,
1091 icqv5_cmd_add_to_list(proto_tree* tree,/* Tree to put the data in */
1092 const u_char* pd, /* Packet content */
1093 int offset, /* Offset from the start of the packet to the content */
1094 int size) /* Number of chars left to do */
1097 proto_tree* subtree;
1100 uin = pletohl(pd + CMD_ADD_TO_LIST);
1102 ti = proto_tree_add_uint_format(tree,
1109 subtree = proto_item_add_subtree(ti, ett_icq_body);
1110 proto_tree_add_text(subtree, NullTVB,
1111 offset + CMD_ADD_TO_LIST_UIN,
1118 icqv5_cmd_status_change(proto_tree* tree,/* Tree to put the data in */
1119 const u_char* pd, /* Packet content */
1120 int offset, /* Offset from the start of the packet to the content */
1121 int size) /* Number of chars left to do */
1123 guint32 status = -1;
1124 proto_tree* subtree;
1127 if (size >= CMD_STATUS_CHANGE_STATUS + 4)
1128 status = pletohl(pd + CMD_STATUS_CHANGE_STATUS);
1130 ti = proto_tree_add_uint_format(tree,
1137 subtree = proto_item_add_subtree(ti, ett_icq_body);
1139 proto_tree_add_text(subtree, NullTVB,
1140 offset + CMD_STATUS_CHANGE_STATUS,
1142 "Status: %08x (%s)", status, findStatus(status));
1147 icqv5_cmd_send_msg(proto_tree* tree,
1153 proto_tree* subtree;
1155 guint32 receiverUIN = 0xffffffff;
1156 guint16 msgType = 0xffff;
1157 guint16 msgLen = 0xffff;
1158 int left = size; /* left chars to do */
1162 receiverUIN = pletohl(pd + CMD_SEND_MSG_RECV_UIN);
1166 msgType = pletohs(pd + CMD_SEND_MSG_MSG_TYPE);
1170 msgLen = pletohs(pd + CMD_SEND_MSG_MSG_LEN);
1174 ti = proto_tree_add_uint_format(tree,
1181 subtree = proto_item_add_subtree(ti, ett_icq_body);
1182 proto_tree_add_text(subtree, NullTVB,
1183 offset + CMD_SEND_MSG_RECV_UIN,
1185 "Receiver UIN: %u", receiverUIN);
1186 proto_tree_add_text(subtree, NullTVB,
1187 offset + CMD_SEND_MSG_MSG_LEN,
1189 "Length: %u", msgLen);
1191 icqv5_decode_msgType(subtree,
1192 pd + CMD_SEND_MSG_MSG_TYPE,
1193 offset + CMD_SEND_MSG_MSG_TYPE,
1194 left+4); /* There are 4 bytes more... */
1199 icqv5_cmd_login(proto_tree* tree,
1205 proto_tree* subtree;
1206 time_t theTime = -1;
1208 guint32 passwdLen = -1;
1209 char* password = NULL;
1210 const u_char *ipAddrp = NULL;
1211 guint32 status = -1;
1212 guint32 left = size;
1215 theTime = pletohl(pd + CMD_LOGIN_TIME);
1218 port = pletohl(pd + CMD_LOGIN_PORT);
1221 passwdLen = pletohs(pd + CMD_LOGIN_PASSLEN);
1223 if (left>=10+passwdLen) {
1224 password = g_malloc(passwdLen + 1);
1225 strncpy(password, pd + CMD_LOGIN_PASSWD, passwdLen);
1226 password[passwdLen] = '\0';
1229 if (left>=10+passwdLen+CMD_LOGIN_IP+4) {
1230 ipAddrp = pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP;
1232 if (left>=10+passwdLen+CMD_LOGIN_STATUS+4) {
1233 status = pletohs(pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS);
1236 ti = proto_tree_add_uint_format(tree,
1243 subtree = proto_item_add_subtree(ti, ett_icq_body);
1245 proto_tree_add_text(subtree, NullTVB,
1246 offset + CMD_LOGIN_TIME,
1248 "Time: %ld = %s", (long)theTime, ctime(&theTime));
1250 proto_tree_add_text(subtree, NullTVB,
1251 offset + CMD_LOGIN_PORT,
1254 if ((passwdLen!=-1) && (password!=NULL))
1255 proto_tree_add_text(subtree, NullTVB,
1256 offset + CMD_LOGIN_PASSLEN,
1258 "Passwd: %s", password);
1260 proto_tree_add_text(subtree, NullTVB,
1261 offset + CMD_LOGIN_PASSWD + CMD_LOGIN_IP,
1263 "IP: %s", ip_to_str(ipAddrp));
1265 proto_tree_add_text(subtree, NullTVB,
1266 offset + CMD_LOGIN_PASSWD + CMD_LOGIN_IP,
1268 "Status: %s", findStatus(status));
1275 icqv5_cmd_contact_list(proto_tree* tree,
1280 proto_tree* subtree;
1282 unsigned char num = -1;
1285 const u_char* p = NULL;
1287 if (size >= CMD_CONTACT_LIST_NUM + 1)
1288 num = pd[CMD_CONTACT_LIST_NUM];
1291 ti = proto_tree_add_uint_format(tree,
1298 subtree = proto_item_add_subtree(ti, ett_icq_body);
1299 proto_tree_add_text(subtree, NullTVB,
1300 offset + CMD_CONTACT_LIST,
1302 "Number of uins: %u", num);
1304 * A sequence of num times UIN follows
1306 offset += (CMD_CONTACT_LIST_NUM + 1);
1308 p = &pd[CMD_CONTACT_LIST_NUM + 1];
1309 for (i = 0; (i<num) && (left>0);i++) {
1312 proto_tree_add_text(subtree, NullTVB,
1315 "UIN[%d]: %u",i,uin);
1325 icqv5_cmd_no_params(proto_tree* tree,/* Tree to put the data in */
1326 const u_char* pd, /* Packet content */
1327 int offset, /* Offset from the start of the packet to the content */
1328 int size, /* Number of chars left to do */
1331 proto_tree* subtree;
1335 ti = proto_tree_add_uint_format(tree,
1342 subtree = proto_item_add_subtree(ti, ett_icq_body);
1343 proto_tree_add_text(subtree, NullTVB,
1350 /**********************
1354 **********************
1357 icqv5_srv_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,
1383 icqv5_srv_login_reply(proto_tree* tree,/* Tree to put the data in */
1384 const u_char* pd, /* Packet content */
1385 int offset, /* Offset from the start of the packet to the content */
1386 int size) /* Number of chars left to do */
1388 proto_tree* subtree;
1390 const u_char *ipAddrp = NULL;
1392 if (size >= SRV_LOGIN_REPLY_IP + 4)
1393 ipAddrp = &pd[SRV_LOGIN_REPLY_IP];
1396 ti = proto_tree_add_uint_format(tree,
1400 SRV_LOGIN_REPLY_IP + 8,
1403 subtree = proto_item_add_subtree(ti, ett_icq_body);
1404 proto_tree_add_text(subtree, NullTVB,
1405 offset + SRV_LOGIN_REPLY_IP,
1407 "IP: %s", ip_to_str(ipAddrp));
1412 icqv5_srv_user_online(proto_tree* tree,/* Tree to put the data in */
1413 const u_char* pd, /* Packet content */
1414 int offset, /* Offset from the start of the packet to the content */
1415 int size) /* Number of chars left to do */
1417 proto_tree* subtree;
1420 const u_char *ipAddrp = NULL;
1422 const u_char *realipAddrp = NULL;
1423 guint32 status = -1;
1424 guint32 version = -1;
1426 if (size >= SRV_USER_ONL_UIN + 4)
1427 uin = pletohl(pd + SRV_USER_ONL_UIN);
1429 if (size >= SRV_USER_ONL_IP + 4)
1430 ipAddrp = &pd[SRV_USER_ONL_IP];
1432 if (size >= SRV_USER_ONL_PORT + 4)
1433 port = pletohl(pd + SRV_USER_ONL_PORT);
1435 if (size >= SRV_USER_ONL_REALIP + 4)
1436 realipAddrp = &pd[SRV_USER_ONL_REALIP];
1438 if (size >= SRV_USER_ONL_STATUS + 2)
1439 status = pletohs(pd + SRV_USER_ONL_STATUS);
1442 * Kojak: Hypothesis is that this field might be an encoding for the
1443 * version used by the UIN that changed. To test this, I included
1444 * this line to the code.
1446 if (size >= SRV_USER_ONL_X2 + 4)
1447 version = pletohl(pd + SRV_USER_ONL_X2);
1450 ti = proto_tree_add_uint_format(tree,
1454 SRV_LOGIN_REPLY_IP + 8,
1457 subtree = proto_item_add_subtree(ti, ett_icq_body);
1458 proto_tree_add_text(subtree, NullTVB,
1459 offset + SRV_USER_ONL_UIN,
1462 proto_tree_add_text(subtree, NullTVB,
1463 offset + SRV_USER_ONL_IP,
1465 "IP: %s", ip_to_str(ipAddrp));
1466 proto_tree_add_text(subtree, NullTVB,
1467 offset + SRV_USER_ONL_PORT,
1470 proto_tree_add_text(subtree, NullTVB,
1471 offset + SRV_USER_ONL_REALIP,
1473 "RealIP: %s", ip_to_str(realipAddrp));
1474 proto_tree_add_text(subtree, NullTVB,
1475 offset + SRV_USER_ONL_STATUS,
1477 "Status: %s", findStatus(status));
1478 proto_tree_add_text(subtree, NullTVB,
1479 offset + SRV_USER_ONL_X2,
1481 "Version: %08x", version);
1486 icqv5_srv_user_offline(proto_tree* tree,/* Tree to put the data in */
1487 const u_char* pd, /* Packet content */
1488 int offset, /* Offset from the start of the packet to the content */
1489 int size) /* Number of chars left to do */
1491 proto_tree* subtree;
1495 if (size >= SRV_USER_OFFLINE + 4)
1496 uin = pletohl(&pd[SRV_USER_OFFLINE]);
1499 ti = proto_tree_add_uint_format(tree,
1503 SRV_USER_OFFLINE_UIN + 4,
1506 subtree = proto_item_add_subtree(ti, ett_icq_body);
1507 proto_tree_add_text(subtree, NullTVB,
1508 offset + SRV_USER_OFFLINE_UIN,
1515 icqv5_srv_multi(proto_tree* tree,/* Tree to put the data in */
1516 const u_char* pd, /* Packet content */
1517 int offset, /* Offset from the start of the packet to the content */
1518 int size, /* Number of chars left to do */
1521 proto_tree* subtree;
1523 unsigned char num = -1;
1526 const u_char* p = NULL;
1528 if (size >= SRV_MULTI_NUM + 1)
1529 num = pd[SRV_MULTI_NUM];
1532 ti = proto_tree_add_uint_format(tree,
1539 subtree = proto_item_add_subtree(ti, ett_icq_body);
1540 proto_tree_add_text(subtree, NullTVB,
1541 offset + SRV_MULTI_NUM,
1543 "Number of pkts: %u", num);
1545 * A sequence of num times ( pktsize, packetData) follows
1547 offset += (SRV_MULTI_NUM + 1);
1549 p = &pd[SRV_MULTI_NUM + 1];
1550 for (i = 0; (i<num) && (left>0);i++) {
1557 dissect_icqv5Server(p, offset, fd, subtree, pktSz);
1568 icqv5_srv_meta_user(proto_tree* tree, /* Tree to put the data in */
1569 const u_char* pd, /* Packet content */
1570 int offset, /* Offset from the start of the packet to the content */
1571 int size) /* Number of chars left to do */
1574 proto_tree* subtree = NULL;
1576 proto_tree* sstree = NULL;
1577 proto_item* ti = NULL;
1581 guint16 subcmd = -1;
1582 unsigned char result = -1;
1584 if (size>=SRV_META_USER_SUBCMD + 2)
1585 subcmd = pletohs(pd+SRV_META_USER_SUBCMD);
1586 if (size>=SRV_META_USER_RESULT + 1)
1587 result = pd[SRV_META_USER_RESULT];
1591 ti = proto_tree_add_uint_format(tree,
1598 subtree = proto_item_add_subtree(ti, ett_icq_body);
1599 ti = proto_tree_add_text(subtree, NullTVB,
1600 offset + SRV_META_USER_SUBCMD,
1602 "%s", findSubCmd(subcmd));
1603 proto_tree_add_text(subtree, NullTVB,
1604 offset + SRV_META_USER_RESULT,
1606 "%s", (result==0x0a)?"Success":"Failure");
1607 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1609 ti = proto_tree_add_text(tree, NullTVB,
1610 offset + SRV_META_USER_SUBCMD,
1612 "%s", findSubCmd(subcmd));
1613 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1614 proto_tree_add_text(sstree, NullTVB,
1615 offset + SRV_META_USER_RESULT,
1617 "%s", (result==0x0a)?"Success":"Failure");
1620 /* Skip the META_USER header */
1625 case META_EX_USER_FOUND:
1627 /* This is almost the same as META_USER_FOUND,
1628 * however, there's an extra length field
1630 guint16 pktLen = -1;
1632 /* Read the lenght field */
1633 pktLen = pletohs(p);
1634 proto_tree_add_text(sstree, NullTVB,
1635 offset + size - left,
1637 "Length: %u", pktLen);
1639 p += sizeof(guint16); left -= sizeof(guint16);
1641 case META_USER_FOUND:
1643 /* The goto mentioned in this block should be local to this
1644 * block if C'd allow it.
1646 * They are used to "implement" a poorman's exception handling
1663 if (left<sizeof(guint32))
1666 proto_tree_add_text(sstree, NullTVB,
1667 offset + size - left,
1670 p+=sizeof(guint32);left-=sizeof(guint32);
1672 for ( ; *d!=NULL; d++) {
1673 len = proto_add_icq_attr(sstree,
1675 offset + size - left,
1680 p += len; left -= len;
1682 /* Get the authorize setting */
1683 if (left<sizeof(unsigned char))
1686 proto_tree_add_text(sstree, NullTVB,
1687 offset + size - left,
1689 "authorization: %s", (auth==0x01)?"Neccessary":"Who needs it");
1692 if (left<sizeof(guint16))
1695 proto_tree_add_text(sstree, NullTVB,
1696 offset + size - left,
1699 p+=sizeof(guint16);left-=sizeof(guint16);
1701 if (left<sizeof(guint32))
1704 proto_tree_add_text(sstree, NullTVB,
1705 offset + size - left,
1708 p+=sizeof(guint32);left-=sizeof(guint32);
1715 /* Get the about information */
1716 if (left<sizeof(guint16))
1719 p+=sizeof(guint16);left-=sizeof(guint16);
1720 if ((len<=0) || (left<len))
1722 about = g_malloc(len);
1723 strncpy(about, p, len);
1724 proto_tree_add_text(sstree, NullTVB,
1725 offset + size - left,
1726 sizeof(guint16)+len,
1727 "About(%d): %s", len, about);
1733 case META_USER_INFO:
1735 /* The goto mentioned in this block should be local to this
1736 * block if C'd allow it.
1738 * They are used to "implement" a poorman's exception handling
1740 static const char* descr[] = {
1755 const char** d = descr;
1758 unsigned char user_timezone = -1;
1759 unsigned char auth = -1;
1763 if (left<sizeof(guint32))
1766 proto_tree_add_text(sstree, NullTVB,
1767 offset + size - left,
1770 p+=sizeof(guint32);left-=sizeof(guint32);
1774 * Get every field from the description
1776 while ((*d)!=NULL) {
1777 if (left<sizeof(guint16))
1780 p+=sizeof(guint16);left-=sizeof(guint16);
1781 if ((len<0) || (left<len))
1784 item = g_malloc(len);
1785 strncpy(item, p, len);
1786 proto_tree_add_text(sstree, NullTVB,
1787 offset + size - left - sizeof(guint16),
1788 sizeof(guint16)+len,
1789 "%s(%d): %s",*d, len, item);
1795 /* Get country code */
1796 if (left<sizeof(guint16))
1798 country = pletohs(p);
1799 proto_tree_add_text(sstree, NullTVB,
1800 offset + size - left,
1802 "Countrycode: %u", country);
1803 p+=sizeof(guint16); left-=sizeof(guint16);
1804 /* Get the timezone setting */
1805 if (left<sizeof(unsigned char))
1808 proto_tree_add_text(sstree, NullTVB,
1809 offset + size - left,
1810 sizeof(unsigned char),
1811 "Timezone: %u", user_timezone);
1813 /* Get the authorize setting */
1814 if (left<sizeof(unsigned char))
1817 proto_tree_add_text(sstree, NullTVB,
1818 offset + size - left,
1819 sizeof(unsigned char),
1820 "Authorization: (%u) %s",
1821 auth, (auth==0)?"No":"Yes");
1823 /* Get the webaware setting */
1824 if (left<sizeof(unsigned char))
1827 proto_tree_add_text(sstree, NullTVB,
1828 offset + size - left,
1829 sizeof(unsigned char),
1830 "Webaware: (%u) %s",
1831 auth, (auth==0)?"No":"Yes");
1833 /* Get the authorize setting */
1834 if (left<sizeof(unsigned char))
1837 proto_tree_add_text(sstree, NullTVB,
1838 offset + size - left,
1839 sizeof(unsigned char),
1841 auth, (auth==0)?"No":"Yes");
1846 /* This information is already printed in the tree */
1847 fprintf(stderr, "Meta subcmd: %04x\n", subcmd);
1854 icqv5_srv_recv_message(proto_tree* tree, /* Tree to put the data in */
1855 const u_char* pd, /* Packet content */
1856 int offset, /* Offset from the start of the packet to the content */
1857 int size) /* Number of chars left to do */
1859 proto_tree* subtree = NULL;
1860 proto_item* ti = NULL;
1864 unsigned char month = -1;
1865 unsigned char day = -1;
1866 unsigned char hour = -1;
1867 unsigned char minute = -1;
1870 ti = proto_tree_add_uint_format(tree,
1877 subtree = proto_item_add_subtree(ti, ett_icq_body);
1878 if (left>=sizeof(guint32)) {
1879 uin = pletohl(pd + SRV_RECV_MSG_UIN);
1880 proto_tree_add_uint_format(subtree,
1883 offset + SRV_RECV_MSG_UIN,
1887 left -= sizeof(guint32);
1890 if (left>=(sizeof(guint16)+4*sizeof(unsigned char))) {
1891 year = pletohs(pd + SRV_RECV_MSG_YEAR);
1892 month = pd[SRV_RECV_MSG_MONTH];
1893 day = pd[SRV_RECV_MSG_DAY];
1894 hour = pd[SRV_RECV_MSG_HOUR];
1895 minute = pd[SRV_RECV_MSG_MINUTE];
1897 proto_tree_add_text(subtree, NullTVB,
1898 offset + SRV_RECV_MSG_YEAR,
1899 sizeof(guint16) + 4*sizeof(unsigned char),
1900 "Time: %u-%u-%u %02u:%02u",
1901 day, month, year, hour, minute);
1903 left -= (sizeof(guint16)+4*sizeof(unsigned char));
1906 icqv5_decode_msgType(subtree,
1907 pd + SRV_RECV_MSG_MSG_TYPE,
1908 offset + SRV_RECV_MSG_MSG_TYPE,
1914 icqv5_srv_rand_user(proto_tree* tree, /* Tree to put the data in */
1915 const u_char* pd, /* Packet content */
1916 int offset, /* Offset from the start of the packet to the content */
1917 int size) /* Number of chars left to do */
1919 proto_tree* subtree = NULL;
1920 proto_item* ti = NULL;
1922 const unsigned char* IP = NULL;
1924 const unsigned char* realIP = NULL;
1925 unsigned char commClass = -1;
1931 ti = proto_tree_add_uint_format(tree,
1935 SRV_RAND_USER_TCP_VER + 2,
1938 subtree = proto_item_add_subtree(ti, ett_icq_body);
1940 if (left<sizeof(guint32))
1942 uin = pletohl(pd + SRV_RAND_USER_UIN);
1943 proto_tree_add_text(subtree, NullTVB,
1944 offset + SRV_RAND_USER_UIN,
1947 left -= sizeof(guint32);
1949 if (left<sizeof(guint32))
1951 IP = pd + SRV_RAND_USER_IP;
1952 proto_tree_add_text(subtree, NullTVB,
1953 offset + SRV_RAND_USER_IP,
1955 "IP: %s", ip_to_str(IP));
1956 left -= sizeof(guint32);
1957 /* guint32 portNum */
1958 if (left<sizeof(guint32))
1960 port = pletohs(pd + SRV_RAND_USER_PORT);
1961 proto_tree_add_text(subtree, NullTVB,
1962 offset + SRV_RAND_USER_UIN,
1965 left -= sizeof(guint32);
1966 /* guint32 realIP */
1967 if (left<sizeof(guint32))
1969 realIP = pd + SRV_RAND_USER_REAL_IP;
1970 proto_tree_add_text(subtree, NullTVB,
1971 offset + SRV_RAND_USER_REAL_IP,
1973 "RealIP: %s", ip_to_str(realIP));
1974 left -= sizeof(guint32);
1975 /* guit16 Communication Class */
1976 if (left<sizeof(unsigned char))
1978 commClass = pd[SRV_RAND_USER_CLASS];
1979 proto_tree_add_text(subtree, NullTVB,
1980 offset + SRV_RAND_USER_CLASS,
1981 sizeof(unsigned char),
1982 "Class: %s", (commClass!=4)?"User to User":"Through Server");
1983 left -= sizeof(unsigned char);
1984 /* guint32 status */
1985 if (left<sizeof(guint32))
1987 status = pletohs(pd + SRV_RAND_USER_STATUS);
1988 proto_tree_add_text(subtree, NullTVB,
1989 offset + SRV_RAND_USER_STATUS,
1991 "Status: (%u) %s", status, findStatus(status));
1992 /* guint16 tcpVersion */
1993 if (left<sizeof(guint16))
1995 tcpVer = pletohs(pd + SRV_RAND_USER_TCP_VER);
1996 proto_tree_add_text(subtree, NullTVB,
1997 offset + SRV_RAND_USER_TCP_VER,
1999 "TCPVersion: %u", tcpVer);
2000 left -= sizeof(guint16);
2005 * Dissect all the v5 client traffic. This is encrypted, so be careful.
2008 dissect_icqv5Client(const u_char *pd,
2013 proto_tree *icq_tree = NULL;
2014 proto_tree *icq_header_tree = NULL;
2015 proto_tree *icq_decode_tree = NULL;
2016 proto_item *ti = NULL;
2018 guint16 version = -1, cmd = -1;
2019 guint16 seqnum1 = 0 , seqnum2 = 0;
2020 guint32 uin = -1, sessionid = -1;
2022 guint16 pktsize = -1; /* The size of the ICQ content */
2023 u_char decr_pd[1600]; /* Decrypted content, size should be dynamic */
2025 pktsize = END_OF_FRAME;
2026 /* First copy the memory, we don't want to overwrite the old content */
2027 memcpy(decr_pd, &pd[offset], pktsize);
2029 key = get_v5key(decr_pd, pktsize);
2030 decrypt_v5(decr_pd, pktsize, key);
2032 /* This information only makes sense in the decrypted version */
2033 uin = pletohl(&decr_pd[ICQ5_CL_UIN]);
2034 cmd = pletohs(&decr_pd[ICQ5_CL_CMD]);
2035 sessionid = pletohl(&decr_pd[ICQ5_CL_SESSIONID]);
2036 version = pletohs(&decr_pd[ICQ_VERSION]);
2037 seqnum1 = pletohs(&decr_pd[ICQ5_CL_SEQNUM1]);
2038 seqnum2 = pletohs(&decr_pd[ICQ5_CL_SEQNUM2]);
2040 if (check_col(fd, COL_INFO))
2041 col_add_fstr(fd, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
2045 ti = proto_tree_add_protocol_format(tree,
2050 "ICQv5 %s (len %u)",
2053 icq_tree = proto_item_add_subtree(ti, ett_icq);
2054 ti = proto_tree_add_uint_format(icq_tree,
2061 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
2063 proto_tree_add_uint_format(icq_header_tree,
2066 offset+ICQ5_CL_SESSIONID,
2069 "Session ID: 0x%08x",
2071 proto_tree_add_uint_format(icq_header_tree,
2074 offset+ICQ5_CL_CHECKCODE,
2079 proto_tree_add_uint_format(icq_header_tree,
2087 proto_tree_add_text(icq_header_tree, NullTVB,
2088 offset + ICQ5_CL_SEQNUM1,
2090 "Seqnum1: 0x%04x", seqnum1);
2091 proto_tree_add_text(icq_header_tree, NullTVB,
2092 offset + ICQ5_CL_SEQNUM1,
2094 "Seqnum2: 0x%04x", seqnum2);
2097 icqv5_cmd_ack(icq_tree,
2098 decr_pd + ICQ5_CL_HDRSIZE,
2099 offset + ICQ5_CL_HDRSIZE,
2100 pktsize - ICQ5_CL_HDRSIZE);
2103 case CMD_MSG_TO_NEW_USER:
2104 icqv5_cmd_send_msg(icq_tree,
2105 decr_pd + ICQ5_CL_HDRSIZE,
2106 offset + ICQ5_CL_HDRSIZE,
2107 pktsize - ICQ5_CL_HDRSIZE,
2110 case CMD_RAND_SEARCH:
2111 icqv5_cmd_rand_search(icq_tree,
2112 decr_pd + ICQ5_CL_HDRSIZE,
2113 offset + ICQ5_CL_HDRSIZE,
2114 pktsize - ICQ5_CL_HDRSIZE);
2117 icqv5_cmd_login(icq_tree,
2118 decr_pd + ICQ5_CL_HDRSIZE,
2119 offset + ICQ5_CL_HDRSIZE,
2120 pktsize - ICQ5_CL_HDRSIZE);
2122 case CMD_SEND_TEXT_CODE:
2123 icqv5_cmd_send_text_code(icq_tree,
2124 decr_pd + ICQ5_CL_HDRSIZE,
2125 offset + ICQ5_CL_HDRSIZE,
2126 pktsize - ICQ5_CL_HDRSIZE);
2128 case CMD_STATUS_CHANGE:
2129 icqv5_cmd_status_change(icq_tree,
2130 decr_pd + ICQ5_CL_HDRSIZE,
2131 offset + ICQ5_CL_HDRSIZE,
2132 pktsize - ICQ5_CL_HDRSIZE);
2134 case CMD_ACK_MESSAGES:
2135 icqv5_cmd_ack_messages(icq_tree,
2136 decr_pd + ICQ5_CL_HDRSIZE,
2137 offset + ICQ5_CL_HDRSIZE,
2138 pktsize - ICQ5_CL_HDRSIZE);
2140 case CMD_KEEP_ALIVE:
2141 icqv5_cmd_keep_alive(icq_tree,
2142 decr_pd + ICQ5_CL_HDRSIZE,
2143 offset + ICQ5_CL_HDRSIZE,
2144 pktsize - ICQ5_CL_HDRSIZE);
2146 case CMD_ADD_TO_LIST:
2147 icqv5_cmd_add_to_list(icq_tree,
2148 decr_pd + ICQ5_CL_HDRSIZE,
2149 offset + ICQ5_CL_HDRSIZE,
2150 pktsize - ICQ5_CL_HDRSIZE);
2152 case CMD_CONTACT_LIST:
2153 icqv5_cmd_contact_list(icq_tree,
2154 decr_pd + ICQ5_CL_HDRSIZE,
2155 offset + ICQ5_CL_HDRSIZE,
2156 pktsize - ICQ5_CL_HDRSIZE);
2159 case CMD_REG_NEW_USER:
2160 case CMD_QUERY_SERVERS:
2161 case CMD_QUERY_ADDONS:
2162 icqv5_cmd_no_params(icq_tree,
2163 decr_pd + ICQ5_CL_HDRSIZE,
2164 offset + ICQ5_CL_HDRSIZE,
2165 pktsize - ICQ5_CL_HDRSIZE,
2169 proto_tree_add_uint_format(icq_tree,
2176 cmd, findClientCmd(cmd));
2177 fprintf(stderr,"Missing: %s\n", findClientCmd(cmd));
2180 ti = proto_tree_add_text(icq_tree, NullTVB,
2184 icq_decode_tree = proto_item_add_subtree(ti,
2186 proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
2192 dissect_icqv5Server(const u_char *pd,
2198 /* Server traffic is easy, not encrypted */
2199 proto_tree *icq_tree = NULL;
2200 proto_tree *icq_header_tree = NULL;
2201 proto_tree *icq_decode_tree = NULL;
2202 proto_item *ti = NULL;
2203 const u_char* decr_pd;
2204 int changeCol = (pktsize==(guint32)-1);
2206 guint16 version, cmd;
2207 guint32 uin, sessionid;
2208 guint16 seq_num1, seq_num2;
2211 uin = pletohl(&pd[ICQ5_SRV_UIN]);
2212 sessionid = pletohl(&pd[ICQ5_SRV_SESSIONID]);
2213 cmd = pletohs(&pd[ICQ5_SRV_CMD]);
2214 version = pletohs(&pd[ICQ_VERSION]);
2215 checkcode = pletohl(&pd[ICQ5_SRV_CHECKCODE]);
2216 seq_num1 = pletohs(&pd[ICQ5_SRV_SEQNUM1]);
2217 seq_num2 = pletohs(&pd[ICQ5_SRV_SEQNUM2]);
2219 pktsize = fd->pkt_len - offset;
2222 if (changeCol && check_col(fd, COL_INFO))
2223 col_add_fstr(fd, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
2226 ti = proto_tree_add_protocol_format(tree,
2231 "ICQv5 %s (len %u)",
2235 icq_tree = proto_item_add_subtree(ti, ett_icq);
2237 ti = proto_tree_add_uint_format(icq_tree,
2244 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
2246 proto_tree_add_uint_format(icq_header_tree,
2249 offset+ICQ5_SRV_SESSIONID,
2252 "Session ID: 0x%08x",
2254 proto_tree_add_text(icq_header_tree, NullTVB,
2255 offset+ICQ5_SRV_SEQNUM1,
2257 "Seq Number1: 0x%04x",
2259 proto_tree_add_text(icq_header_tree, NullTVB,
2260 offset+ICQ5_SRV_SEQNUM2,
2262 "Seq Number2: 0x%04x",
2264 proto_tree_add_uint_format(icq_header_tree,
2267 offset+ICQ5_SRV_UIN,
2272 proto_tree_add_uint_format(icq_header_tree,
2275 offset+ICQ5_SRV_CHECKCODE,
2278 "Checkcode: 0x%08x",
2282 icqv5_srv_rand_user(icq_tree,
2283 decr_pd + ICQ5_SRV_HDRSIZE,
2284 offset + ICQ5_SRV_HDRSIZE,
2285 pktsize - ICQ5_SRV_HDRSIZE);
2287 case SRV_SYS_DELIVERED_MESS:
2288 /* The message structures are all the same. Why not run
2289 * the same routine? */
2290 icqv5_cmd_send_msg(icq_tree,
2291 decr_pd + ICQ5_SRV_HDRSIZE,
2292 offset + ICQ5_SRV_HDRSIZE,
2293 pktsize - ICQ5_SRV_HDRSIZE,
2296 case SRV_USER_ONLINE:
2297 icqv5_srv_user_online(icq_tree,
2298 decr_pd + ICQ5_SRV_HDRSIZE,
2299 offset + ICQ5_SRV_HDRSIZE,
2300 pktsize - ICQ5_SRV_HDRSIZE);
2302 case SRV_USER_OFFLINE:
2303 icqv5_srv_user_offline(icq_tree,
2304 decr_pd + ICQ5_SRV_HDRSIZE,
2305 offset + ICQ5_SRV_HDRSIZE,
2306 pktsize - ICQ5_SRV_HDRSIZE);
2308 case SRV_LOGIN_REPLY:
2309 icqv5_srv_login_reply(icq_tree,
2310 decr_pd + ICQ5_SRV_HDRSIZE,
2311 offset + ICQ5_SRV_HDRSIZE,
2312 pktsize - ICQ5_SRV_HDRSIZE);
2315 icqv5_srv_meta_user(icq_tree,
2316 decr_pd + ICQ5_SRV_HDRSIZE,
2317 offset + ICQ5_SRV_HDRSIZE,
2318 pktsize - ICQ5_SRV_HDRSIZE);
2320 case SRV_RECV_MESSAGE:
2321 icqv5_srv_recv_message(icq_tree,
2322 decr_pd + ICQ5_SRV_HDRSIZE,
2323 offset + ICQ5_SRV_HDRSIZE,
2324 pktsize - ICQ5_SRV_HDRSIZE);
2327 icqv5_srv_multi(icq_tree,
2328 decr_pd + ICQ5_SRV_HDRSIZE,
2329 offset + ICQ5_SRV_HDRSIZE,
2330 pktsize - ICQ5_SRV_HDRSIZE,
2337 case SRV_UPDATE_SUCCESS:
2338 icqv5_srv_no_params(icq_tree,
2339 decr_pd + ICQ5_SRV_HDRSIZE,
2340 offset + ICQ5_SRV_HDRSIZE,
2341 pktsize - ICQ5_SRV_HDRSIZE,
2345 proto_tree_add_uint_format(icq_tree,
2348 offset + ICQ5_SRV_CMD,
2352 cmd, findServerCmd(cmd));
2353 fprintf(stderr,"Missing: %s\n", findServerCmd(cmd));
2357 ti = proto_tree_add_text(icq_tree, NullTVB,
2361 icq_decode_tree = proto_item_add_subtree(ti,
2363 proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
2367 static void dissect_icqv5(const u_char *pd,
2372 guint32 unknown = pletohl(&pd[offset + ICQ5_UNKNOWN]);
2374 if (check_col(fd, COL_PROTOCOL))
2375 col_add_str(fd, COL_PROTOCOL, "ICQv5 (UDP)");
2376 if (check_col(fd, COL_INFO))
2377 col_add_str(fd, COL_INFO, "ICQv5 packet");
2378 if (unknown == 0x0L) {
2379 dissect_icqv5Client(pd, offset, fd, tree);
2381 dissect_icqv5Server(pd + offset, offset, fd, tree, (guint32) -1);
2385 static void dissect_icq(const u_char *pd,
2392 version = pletohs(&pd[offset + ICQ_VERSION]);
2395 dissect_icqv5(pd, offset, fd, tree);
2398 dissect_icqv2(pd, offset, fd, tree);
2401 fprintf(stderr, "ICQ: Unknown version (%d)\n", version);
2406 /* registration with the filtering engine */
2408 proto_register_icq(void)
2410 static hf_register_info hf[] = {
2412 {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2414 {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, ""}},
2415 { &hf_icq_sessionid,
2416 {"SessionID", "icq.sessionid", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2418 {"Command", "icq.cmd", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2419 { &hf_icq_checkcode,
2420 {"Checkcode", "icq.checkcode", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2422 {"Decode", "icq.decode", FT_STRING, BASE_NONE, NULL, 0x0, ""}}
2424 static gint *ett[] = {
2429 &ett_icq_body_parts,
2432 proto_icq = proto_register_protocol ("ICQ Protocol", "icq");
2434 proto_register_field_array(proto_icq, hf, array_length(hf));
2436 proto_register_subtree_array(ett, array_length(ett));
2440 proto_reg_handoff_icq(void)
2442 dissector_add("udp.port", UDP_PORT_ICQ, dissect_icq);