2 * Routines for ICQ packet disassembly
4 * $Id: packet-icq.c,v 1.40 2002/02/25 07:56:59 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * This file: by Kojak <kojak@bigwig.net>
28 * Decoding code ripped, reference to the original author at the
29 * appropriate place with the code itself.
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
48 #ifdef HAVE_ARPA_INET_H
49 #include <arpa/inet.h>
60 #ifdef NEED_SNPRINTF_H
61 # include "snprintf.h"
64 #include <epan/packet.h>
65 #include <epan/resolv.h>
67 static int proto_icq = -1;
68 static int hf_icq_uin = -1;
69 static int hf_icq_client_cmd = -1;
70 static int hf_icq_server_cmd = -1;
71 static int hf_icq_sessionid = -1;
72 static int hf_icq_checkcode = -1;
73 static int hf_icq_decode = -1;
74 static int hf_icq_type = -1;
76 static gint ett_icq = -1;
77 static gint ett_icq_header = -1;
78 static gint ett_icq_decode = -1;
79 static gint ett_icq_body = -1;
80 static gint ett_icq_body_parts = -1;
82 #define UDP_PORT_ICQ 4000
84 enum { ICQ5_client, ICQ5_server};
86 static void dissect_icqv5(tvbuff_t *tvb,
91 dissect_icqv5Server(tvbuff_t *tvb,
97 /* Offsets of fields in the ICQ headers */
98 /* Can be 0x0002 or 0x0005 */
99 #define ICQ_VERSION 0x00
100 /* Is either one (server) or four (client) bytes long */
101 /* Client header offsets */
102 #define ICQ5_UNKNOWN 0x02
103 #define ICQ5_CL_UIN 0x06
104 #define ICQ5_CL_SESSIONID 0x0a
105 #define ICQ5_CL_CMD 0x0e
106 #define ICQ5_CL_SEQNUM1 0x10
107 #define ICQ5_CL_SEQNUM2 0x12
108 #define ICQ5_CL_CHECKCODE 0x14
109 #define ICQ5_CL_PARAM 0x18
110 #define ICQ5_CL_HDRSIZE 0x18
112 /* Server header offsets */
113 #define ICQ5_SRV_SESSIONID 0x03
114 #define ICQ5_SRV_CMD 0x07
115 #define ICQ5_SRV_SEQNUM1 0x09
116 #define ICQ5_SRV_SEQNUM2 0x0b
117 #define ICQ5_SRV_UIN 0x0d
118 #define ICQ5_SRV_CHECKCODE 0x11
119 #define ICQ5_SRV_PARAM 0x15
120 #define ICQ5_SRV_HDRSIZE 0x15
122 #define SRV_ACK 0x000a
124 #define SRV_SILENT_TOO_LONG 0x001e
126 #define SRV_GO_AWAY 0x0028
128 #define SRV_NEW_UIN 0x0046
130 /* LOGIN_REPLY is very scary. It has a lot of fields that are undocumented
131 * Only the IP field makes sense */
132 #define SRV_LOGIN_REPLY 0x005a
133 #define SRV_LOGIN_REPLY_IP 0x000c
135 #define SRV_BAD_PASS 0x0064
137 #define SRV_USER_ONLINE 0x006e
138 #define SRV_USER_ONL_UIN 0x0000
139 #define SRV_USER_ONL_IP 0x0004
140 #define SRV_USER_ONL_PORT 0x0008
141 #define SRV_USER_ONL_REALIP 0x000c
142 #define SRV_USER_ONL_X1 0x0010
143 #define SRV_USER_ONL_STATUS 0x0013
144 #define SRV_USER_ONL_X2 0x0015
146 #define SRV_USER_OFFLINE 0x0078
147 #define SRV_USER_OFFLINE_UIN 0x0000
149 #define SRV_MULTI 0x0212
150 #define SRV_MULTI_NUM 0x0000
152 #define SRV_META_USER 0x03de
153 #define SRV_META_USER_SUBCMD 0x0000
154 #define SRV_META_USER_RESULT 0x0002
155 #define SRV_META_USER_DATA 0x0003
157 #define SRV_UPDATE_SUCCESS 0x01e0
159 #define SRV_UPDATE_FAIL 0x01ea
162 * ICQv5 SRV_META_USER subcommands
164 #define META_EX_USER_FOUND 0x0190
165 #define META_USER_FOUND 0x019a
166 #define META_ABOUT 0x00e6
167 #define META_USER_INFO 0x00c8
169 #define SRV_RECV_MESSAGE 0x00dc
170 #define SRV_RECV_MSG_UIN 0x0000
171 #define SRV_RECV_MSG_YEAR 0x0004
172 #define SRV_RECV_MSG_MONTH 0x0006
173 #define SRV_RECV_MSG_DAY 0x0007
174 #define SRV_RECV_MSG_HOUR 0x0008
175 #define SRV_RECV_MSG_MINUTE 0x0009
176 #define SRV_RECV_MSG_MSG_TYPE 0x000a
178 #define SRV_RAND_USER 0x024e
179 #define SRV_RAND_USER_UIN 0x0000
180 #define SRV_RAND_USER_IP 0x0004
181 #define SRV_RAND_USER_PORT 0x0008
182 #define SRV_RAND_USER_REAL_IP 0x000c
183 #define SRV_RAND_USER_CLASS 0x0010
184 #define SRV_RAND_USER_X1 0x0011
185 #define SRV_RAND_USER_STATUS 0x0015
186 #define SRV_RAND_USER_TCP_VER 0x0019
188 /* This message has the same structure as cmd_send_msg */
189 #define SRV_SYS_DELIVERED_MESS 0x0104
191 static const value_string serverMetaSubCmdCode[] = {
192 { META_USER_FOUND, "META_USER_FOUND" },
193 { META_EX_USER_FOUND, "META_EX_USER_FOUND" },
194 { META_ABOUT, "META_ABOUT" },
195 { META_USER_INFO, "META_USER_INFO" },
199 static const value_string serverCmdCode[] = {
200 { SRV_ACK, "SRV_ACK" },
201 { SRV_SILENT_TOO_LONG, "SRV_SILENT_TOO_LONG" },
202 { SRV_GO_AWAY, "SRV_GO_AWAY" },
203 { SRV_NEW_UIN, "SRV_NEW_UIN" },
204 { SRV_LOGIN_REPLY, "SRV_LOGIN_REPLY" },
205 { SRV_BAD_PASS, "SRV_BAD_PASS" },
206 { SRV_USER_ONLINE, "SRV_USER_ONLINE" },
207 { SRV_USER_OFFLINE, "SRV_USER_OFFLINE" },
208 { 130, "SRV_QUERY" },
209 { 140, "SRV_USER_FOUND" },
210 { 160, "SRV_END_OF_SEARCH" },
211 { 180, "SRV_NEW_USER" },
212 { 200, "SRV_UPDATE_EXT" },
213 { SRV_RECV_MESSAGE, "SRV_RECV_MESSAGE" },
214 { 230, "SRV_END_OFFLINE_MESSAGES" },
215 { 240, "SRV_NOT_CONNECTED" },
216 { 250, "SRV_TRY_AGAIN" },
217 { SRV_SYS_DELIVERED_MESS, "SRV_SYS_DELIVERED_MESS" },
218 { 280, "SRV_INFO_REPLY" },
219 { 290, "SRV_EXT_INFO_REPLY" },
220 { 420, "SRV_STATUS_UPDATE" },
221 { 450, "SRV_SYSTEM_MESSAGE" },
222 { SRV_UPDATE_SUCCESS, "SRV_UPDATE_SUCCESS" },
223 { SRV_UPDATE_FAIL, "SRV_UPDATE_FAIL" },
224 { 500, "SRV_AUTH_UPDATE" },
225 { SRV_MULTI, "SRV_MULTI_PACKET" },
226 { 540, "SRV_END_CONTACTLIST_STATUS" },
227 { SRV_RAND_USER, "SRV_RAND_USER" },
228 { SRV_META_USER, "SRV_META_USER" },
232 #define MSG_TEXT 0x0001
233 #define MSG_URL 0x0004
234 #define MSG_AUTH_REQ 0x0006
235 #define MSG_AUTH 0x0008
236 #define MSG_USER_ADDED 0x000c
237 #define MSG_EMAIL 0x000e
238 #define MSG_CONTACTS 0x0013
240 #define STATUS_ONLINE 0x00000000
241 #define STATUS_AWAY 0x00000001
242 #define STATUS_DND 0x00000013
243 #define STATUS_INVISIBLE 0x00000100
244 #define STATUS_OCCUPIED 0x00000010
245 #define STATUS_NA 0x00000004
246 #define STATUS_CHAT 0x00000020
248 /* Offsets for all packets measured from the start of the payload; i.e.
249 * with the ICQ header removed
251 #define CMD_ACK 0x000a
252 #define CMD_ACK_RANDOM 0x0000
254 #define CMD_SEND_MSG 0x010E
255 #define CMD_SEND_MSG_RECV_UIN 0x0000
256 #define CMD_SEND_MSG_MSG_TYPE 0x0004
257 #define CMD_SEND_MSG_MSG_LEN 0x0006
258 #define CMD_SEND_MSG_MSG_TEXT 0x0008
259 /* The rest of the packet should be a null-term string */
261 #define CMD_LOGIN 0x03E8
262 #define CMD_LOGIN_TIME 0x0000
263 #define CMD_LOGIN_PORT 0x0004
264 #define CMD_LOGIN_PASSLEN 0x0008
265 #define CMD_LOGIN_PASSWD 0x000A
266 /* The password is variable length; so when we've decoded the passwd,
267 * the structure starts counting at 0 again.
269 #define CMD_LOGIN_IP 0x0004
270 #define CMD_LOGIN_STATUS 0x0009
272 #define CMD_CONTACT_LIST 0x0406
273 #define CMD_CONTACT_LIST_NUM 0x0000
275 #define CMD_USER_META 0x064a
277 #define CMD_REG_NEW_USER 0x03fc
279 #define CMD_ACK_MESSAGES 0x0442
280 #define CMD_ACK_MESSAGES_RANDOM 0x0000
282 #define CMD_KEEP_ALIVE 0x042e
283 #define CMD_KEEP_ALIVE_RANDOM 0x0000
285 #define CMD_SEND_TEXT_CODE 0x0438
286 #define CMD_SEND_TEXT_CODE_LEN 0x0000
287 #define CMD_SEND_TEXT_CODE_TEXT 0x0002
289 #define CMD_MSG_TO_NEW_USER 0x0456
291 #define CMD_QUERY_SERVERS 0x04ba
293 #define CMD_QUERY_ADDONS 0x04c4
295 #define CMD_STATUS_CHANGE 0x04d8
296 #define CMD_STATUS_CHANGE_STATUS 0x0000
298 #define CMD_ADD_TO_LIST 0x053c
299 #define CMD_ADD_TO_LIST_UIN 0x0000
301 #define CMD_RAND_SEARCH 0x056e
302 #define CMD_RAND_SEARCH_GROUP 0x0000
304 #define CMD_META_USER 0x064a
306 static const value_string msgTypeCode[] = {
307 { MSG_TEXT, "MSG_TEXT" },
308 { MSG_URL, "MSG_URL" },
309 { MSG_AUTH_REQ, "MSG_AUTH_REQ" },
310 { MSG_AUTH, "MSG_AUTH" },
311 { MSG_USER_ADDED, "MSG_USER_ADDED" },
312 { MSG_EMAIL, "MSG_EMAIL" },
313 { MSG_CONTACTS, "MSG_CONTACTS" },
317 static const value_string statusCode[] = {
318 { STATUS_ONLINE, "ONLINE" },
319 { STATUS_AWAY, "AWAY" },
320 { STATUS_DND, "DND" },
321 { STATUS_INVISIBLE, "INVISIBLE" },
322 { STATUS_OCCUPIED, "OCCUPIED" },
324 { STATUS_CHAT, "Free for Chat" },
328 static const value_string clientCmdCode[] = {
329 { CMD_ACK, "CMD_ACK" },
330 { CMD_SEND_MSG, "CMD_SEND_MESSAGE" },
331 { CMD_LOGIN, "CMD_LOGIN" },
332 { CMD_REG_NEW_USER, "CMD_REG_NEW_USER" },
333 { 1030, "CMD_CONTACT_LIST" },
334 { 1050, "CMD_SEARCH_UIN" },
335 { 1060, "CMD_SEARCH_USER" },
336 { 1070, "CMD_KEEP_ALIVE" },
337 { CMD_SEND_TEXT_CODE, "CMD_SEND_TEXT_CODE" },
338 { CMD_ACK_MESSAGES, "CMD_ACK_MESSAGES" },
339 { 1100, "CMD_LOGIN_1" },
340 { CMD_MSG_TO_NEW_USER, "CMD_MSG_TO_NEW_USER" },
341 { 1120, "CMD_INFO_REQ" },
342 { 1130, "CMD_EXT_INFO_REQ" },
343 { 1180, "CMD_CHANGE_PW" },
344 { 1190, "CMD_NEW_USER_INFO" },
345 { 1200, "CMD_UPDATE_EXT_INFO" },
346 { CMD_QUERY_SERVERS, "CMD_QUERY_SERVERS" },
347 { CMD_QUERY_ADDONS, "CMD_QUERY_ADDONS" },
348 { CMD_STATUS_CHANGE, "CMD_STATUS_CHANGE" },
349 { 1260, "CMD_NEW_USER_1" },
350 { 1290, "CMD_UPDATE_INFO" },
351 { 1300, "CMD_AUTH_UPDATE" },
352 { 1310, "CMD_KEEP_ALIVE2" },
353 { 1320, "CMD_LOGIN_2" },
354 { CMD_ADD_TO_LIST, "CMD_ADD_TO_LIST" },
355 { 1380, "CMD_RAND_SET" },
356 { CMD_RAND_SEARCH, "CMD_RAND_SEARCH" },
357 { CMD_META_USER, "CMD_META_USER" },
358 { 1700, "CMD_INVIS_LIST" },
359 { 1710, "CMD_VIS_LIST" },
360 { 1720, "CMD_UPDATE_LIST" },
365 * All ICQv5 decryption code thanx to Sebastien Dault (daus01@gel.usherb.ca)
369 0x59, 0x60, 0x37, 0x6B, 0x65, 0x62, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x60, 0x57, 0x5B, 0x3D,
370 0x5E, 0x34, 0x6D, 0x36, 0x50, 0x3F, 0x6F, 0x67, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x47, 0x63, 0x39,
371 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x43, 0x69, 0x48, 0x33, 0x31, 0x64, 0x35, 0x5A, 0x4A, 0x42,
372 0x56, 0x40, 0x67, 0x53, 0x41, 0x07, 0x6C, 0x49, 0x58, 0x3B, 0x4D, 0x46, 0x68, 0x43, 0x69, 0x48,
373 0x33, 0x31, 0x44, 0x65, 0x62, 0x46, 0x48, 0x53, 0x41, 0x07, 0x6C, 0x69, 0x48, 0x33, 0x51, 0x54,
374 0x5D, 0x4E, 0x6C, 0x49, 0x38, 0x4B, 0x55, 0x4A, 0x62, 0x46, 0x48, 0x33, 0x51, 0x34, 0x6D, 0x36,
375 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x63, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64, 0x35, 0x5A,
376 0x6A, 0x52, 0x6E, 0x3C, 0x51, 0x34, 0x6D, 0x36, 0x50, 0x5F, 0x5F, 0x3F, 0x4F, 0x37, 0x4B, 0x35,
377 0x5A, 0x4A, 0x62, 0x66, 0x58, 0x3B, 0x4D, 0x66, 0x58, 0x5B, 0x5D, 0x4E, 0x6C, 0x49, 0x58, 0x3B,
378 0x4D, 0x66, 0x58, 0x3B, 0x4D, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64,
379 0x55, 0x6A, 0x32, 0x3E, 0x44, 0x45, 0x52, 0x6E, 0x3C, 0x31, 0x64, 0x55, 0x6A, 0x52, 0x4E, 0x6C,
380 0x69, 0x48, 0x53, 0x61, 0x4C, 0x39, 0x30, 0x6F, 0x47, 0x63, 0x59, 0x60, 0x57, 0x5B, 0x3D, 0x3E,
381 0x64, 0x35, 0x3A, 0x3A, 0x5A, 0x6A, 0x52, 0x4E, 0x6C, 0x69, 0x48, 0x53, 0x61, 0x6C, 0x49, 0x58,
382 0x3B, 0x4D, 0x46, 0x68, 0x63, 0x39, 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x67, 0x53, 0x41, 0x25, 0x41,
383 0x3C, 0x51, 0x54, 0x3D, 0x5E, 0x54, 0x5D, 0x4E, 0x4C, 0x39, 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F,
384 0x47, 0x43, 0x69, 0x48, 0x33, 0x51, 0x54, 0x5D, 0x6E, 0x3C, 0x31, 0x64, 0x35, 0x5A, 0x00, 0x00 };
389 return val_to_str(num, msgTypeCode, "Unknown");
395 return val_to_str(num, serverMetaSubCmdCode, "Unknown (0x%04x)");
399 findClientCmd(int num)
401 return val_to_str(num, clientCmdCode, "Unknown (%u)");
405 findServerCmd(int num)
407 return val_to_str(num, serverCmdCode, "Unknown (%u)");
413 return val_to_str(num, statusCode, "Unknown (0x%08x)");
417 get_v5key(tvbuff_t *tvb, int len)
419 guint32 a1, a2, a3, a4, a5;
420 guint32 code, check, key;
422 code = tvb_get_letohl(tvb, ICQ5_CL_CHECKCODE);
424 a1 = code & 0x0001f000;
425 a2 = code & 0x07c007c0;
426 a3 = code & 0x003e0001;
427 a4 = code & 0xf8000000;
428 a5 = code & 0x0000083e;
436 check = a5 + a1 + a2 + a3 + a4;
437 key = len * 0x68656C6C;
443 decrypt_v5(u_char *bfr, guint32 size,guint32 key)
448 for (i=ICQ5_CL_SESSIONID; i < size; i+=4 ) {
449 k = key+table_v5[i&0xff];
451 bfr[i] ^= (u_char)(k & 0xff);
452 bfr[i+1] ^= (u_char)((k & 0xff00)>>8);
455 bfr[i+2] ^= (u_char)((k & 0xff0000)>>16);
456 bfr[i+3] ^= (u_char)((k & 0xff000000)>>24);
462 dissect_icqv4(tvbuff_t *tvb,
466 /* Not really implemented yet */
467 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
468 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQv4 (UDP)");
470 if (check_col(pinfo->cinfo, COL_INFO)) {
471 col_set_str(pinfo->cinfo, COL_INFO, "ICQ Version 4 protocol");
476 dissect_icqv3(tvbuff_t *tvb,
480 /* Not really implemented yet */
481 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
482 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQv3 (UDP)");
484 if (check_col(pinfo->cinfo, COL_INFO)) {
485 col_set_str(pinfo->cinfo, COL_INFO, "ICQ Version 3 protocol");
490 dissect_icqv2(tvbuff_t *tvb,
494 /* Not really implemented yet */
495 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
496 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQv2 (UDP)");
498 if (check_col(pinfo->cinfo, COL_INFO)) {
499 col_set_str(pinfo->cinfo, COL_INFO, "ICQ Version 2 protocol");
504 * The packet has, at offset "offset" a (len, string) pair.
505 * Display the length and string in the tree.
507 * If anything is wrong, return -1, since -1 is not a valid string
508 * length. Else, return the number of chars processed.
511 proto_add_icq_attr(proto_tree* tree, /* The tree to add to */
512 tvbuff_t *tvb, /* Tvbuff with packet */
513 const int offset, /* Offset from the start of packet of field */
514 char* descr) /* The description to use in the tree */
518 len = tvb_get_letohs(tvb, offset);
519 if (len > tvb_reported_length_remaining(tvb, offset))
520 return -1; /* length goes past end of packet */
521 proto_tree_add_text(tree, tvb,
523 sizeof(guint16) + len,
524 "%s[%u]: %.*s", descr, len, len,
525 tvb_get_ptr(tvb, offset + sizeof(guint16), len));
526 return len + sizeof(guint16);
530 icqv5_decode_msgType(proto_tree* tree,
535 proto_item* ti = NULL;
536 proto_tree* subtree = NULL;
540 int sz; /* Size of the current element */
542 static char* url_field_descr[] = {
546 #define N_URL_FIELDS (sizeof url_field_descr / sizeof url_field_descr[0])
547 static char* email_field_descr[] = {
555 #define N_EMAIL_FIELDS (sizeof email_field_descr / sizeof email_field_descr[0])
556 static char* auth_req_field_descr[] = {
564 #define N_AUTH_REQ_FIELDS (sizeof auth_req_field_descr / sizeof auth_req_field_descr[0])
565 static char* user_added_field_descr[] = {
571 #define N_USER_ADDED_FIELDS (sizeof user_added_field_descr / sizeof user_added_field_descr[0])
573 msgType = tvb_get_letohs(tvb, offset);
574 ti = proto_tree_add_text(tree, tvb,
577 "Message: Type = %u (%s)", msgType, findMsgType(msgType));
578 /* Create a new subtree */
579 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
581 proto_tree_add_text(subtree, tvb,
584 "Type: %u (%s)", msgType, findMsgType(msgType));
587 if (msgType != MSG_AUTH) {
589 * XXX - does a MSG_AUTH message really have 3 bytes of information
590 * rather than a length field?
592 proto_tree_add_text(subtree, tvb,
596 tvb_get_letohs(tvb, offset));
602 case 0xffff: /* Field unknown */
605 fprintf(stderr, "Unknown msgType: %u (%04x)\n", msgType, msgType);
608 proto_tree_add_text(subtree, tvb,
612 tvb_get_ptr(tvb, offset, left));
615 for (n = 0; n < N_URL_FIELDS; n++) {
616 if (n != N_URL_FIELDS - 1) {
617 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
618 sz = sep_offset - offset + 1;
622 proto_tree_add_text(subtree, tvb,
628 tvb_get_ptr(tvb, offset, sz));
630 proto_tree_add_text(subtree, tvb,
633 "%s: %s", url_field_descr[n], "(empty)");
640 for (n = 0; n < N_EMAIL_FIELDS; n++) {
641 if (n != N_EMAIL_FIELDS - 1) {
642 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
643 sz = sep_offset - offset + 1;
647 proto_tree_add_text(subtree, tvb,
651 email_field_descr[n],
653 tvb_get_ptr(tvb, offset, sz));
655 proto_tree_add_text(subtree, tvb,
658 "%s: %s", email_field_descr[n], "(empty)");
667 /* Three bytes, first is a char signifying success */
668 unsigned char auth_suc;
670 auth_suc = tvb_get_guint8(tvb, offset);
671 proto_tree_add_text(subtree, tvb,
674 "Authorization: (%u) %s",auth_suc,
675 (auth_suc==0)?"Denied":"Allowed");
677 proto_tree_add_text(subtree, tvb,
681 tvb_get_letohs(tvb, offset));
685 for (n = 0; n < N_AUTH_REQ_FIELDS; n++) {
686 if (n != N_AUTH_REQ_FIELDS - 1) {
687 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
688 sz = sep_offset - offset + 1;
692 proto_tree_add_text(subtree, tvb,
696 auth_req_field_descr[n],
698 tvb_get_ptr(tvb, offset, sz));
700 proto_tree_add_text(subtree, tvb,
703 "%s: %s", auth_req_field_descr[n], "(empty)");
710 for (n = 0; n < N_USER_ADDED_FIELDS; n++) {
711 if (n != N_USER_ADDED_FIELDS - 1) {
712 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
713 sz = sep_offset - offset + 1;
717 proto_tree_add_text(subtree, tvb,
721 user_added_field_descr[n],
723 tvb_get_ptr(tvb, offset, sz));
725 proto_tree_add_text(subtree, tvb,
728 "%s: %s", user_added_field_descr[n], "(empty)");
736 gint sep_offset_prev;
737 int sz = 0; /* Size of the current element */
738 int n = 0; /* The nth element */
739 gboolean last = FALSE;
742 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
743 if (sep_offset != -1)
744 sz = sep_offset - offset + 1;
750 /* The first element is the number of Nick/UIN pairs follow */
751 proto_tree_add_text(subtree, tvb,
754 "Number of pairs: %.*s",
756 tvb_get_ptr(tvb, offset, sz));
762 sep_offset_prev = sep_offset;
763 sep_offset = tvb_find_guint8(tvb, sep_offset_prev, left,
765 if (sep_offset != -1)
766 sz = sep_offset - offset + 1;
771 proto_tree_add_text(subtree, tvb,
776 tvb_get_ptr(tvb, offset, svsz),
778 tvb_get_ptr(tvb, sep_offset_prev + 1, sz));
783 offset = sep_offset + 1;
790 /*********************************
794 *********************************/
796 icqv5_cmd_ack(proto_tree* tree,/* Tree to put the data in */
797 tvbuff_t *tvb, /* Tvbuff with decrypted packet data */
798 int offset) /* Offset from the start of the packet to the content */
804 ti = proto_tree_add_text(tree,
809 subtree = proto_item_add_subtree(ti, ett_icq_body);
810 proto_tree_add_text(subtree, tvb,
811 offset + CMD_ACK_RANDOM,
814 tvb_get_letohl(tvb, offset + CMD_ACK_RANDOM));
819 icqv5_cmd_rand_search(proto_tree* tree, /* Tree to put the data in */
820 tvbuff_t *tvb, /* Decrypted packet content */
821 int offset, /* Offset from the start of the packet to the content */
822 int size) /* Number of chars left to do */
828 static const char* groups[] = {
843 ti = proto_tree_add_text(tree,
848 subtree = proto_item_add_subtree(ti, ett_icq_body);
849 group = tvb_get_letohs(tvb, offset + CMD_RAND_SEARCH_GROUP);
850 if (group>0 && (group<=sizeof(groups)/sizeof(const char*)))
851 proto_tree_add_text(subtree, tvb,
852 offset + CMD_RAND_SEARCH_GROUP,
854 "Group: (%u) %s", group, groups[group-1]);
856 proto_tree_add_text(subtree, tvb,
857 offset + CMD_RAND_SEARCH_GROUP,
859 "Group: (%u)", group);
864 icqv5_cmd_ack_messages(proto_tree* tree, /* Tree to put the data in */
865 tvbuff_t *tvb, /* Decrypted packet content */
866 int offset) /* Offset from the start of the packet to the content */
872 ti = proto_tree_add_text(tree,
877 subtree = proto_item_add_subtree(ti, ett_icq_body);
878 proto_tree_add_text(subtree, tvb,
879 offset + CMD_ACK_MESSAGES_RANDOM,
882 tvb_get_letohl(tvb, offset + CMD_ACK_MESSAGES_RANDOM));
887 icqv5_cmd_keep_alive(proto_tree* tree, /* Tree to put the data in */
888 tvbuff_t *tvb, /* Decrypted packet content */
889 int offset) /* Offset from the start of the packet to the content */
896 ti = proto_tree_add_text(tree,
901 subtree = proto_item_add_subtree(ti, ett_icq_body);
902 random = tvb_get_letohl(tvb, offset + CMD_KEEP_ALIVE_RANDOM);
903 proto_tree_add_text(subtree, tvb,
904 offset + CMD_KEEP_ALIVE_RANDOM,
906 "Random: 0x%08x", random);
911 icqv5_cmd_send_text_code(proto_tree* tree, /* Tree to put the data in */
912 tvbuff_t *tvb, /* Decrypted packet content */
913 int offset, /* Offset from the start of the packet to the content */
914 int size) /* Number of chars left to do */
916 proto_tree* subtree = NULL;
917 proto_item* ti = NULL;
922 ti = proto_tree_add_text(tree,
929 len = tvb_get_letohs(tvb, offset+CMD_SEND_TEXT_CODE_LEN);
931 subtree = proto_item_add_subtree(ti, ett_icq_body);
932 proto_tree_add_text(subtree, tvb,
933 offset + CMD_SEND_TEXT_CODE_LEN,
940 proto_tree_add_text(subtree, tvb,
941 offset + CMD_SEND_TEXT_CODE_TEXT,
945 tvb_get_ptr(tvb, offset + CMD_SEND_TEXT_CODE_TEXT,
950 x1 = tvb_get_letohs(tvb, offset + CMD_SEND_TEXT_CODE_TEXT + len);
952 proto_tree_add_text(subtree, tvb,
953 offset + CMD_SEND_TEXT_CODE_TEXT + len,
960 icqv5_cmd_add_to_list(proto_tree* tree, /* Tree to put the data in */
961 tvbuff_t *tvb, /* Decrypted packet content */
962 int offset) /* Offset from the start of the packet to the content */
969 ti = proto_tree_add_text(tree,
974 subtree = proto_item_add_subtree(ti, ett_icq_body);
975 uin = tvb_get_letohl(tvb, offset + CMD_ADD_TO_LIST);
976 proto_tree_add_text(subtree, tvb,
977 offset + CMD_ADD_TO_LIST_UIN,
984 icqv5_cmd_status_change(proto_tree* tree, /* Tree to put the data in */
985 tvbuff_t *tvb, /* Decrypted packet content */
986 int offset) /* Offset from the start of the packet to the content */
993 ti = proto_tree_add_text(tree,
998 subtree = proto_item_add_subtree(ti, ett_icq_body);
999 status = tvb_get_letohl(tvb, offset + CMD_STATUS_CHANGE_STATUS);
1000 proto_tree_add_text(subtree, tvb,
1001 offset + CMD_STATUS_CHANGE_STATUS,
1003 "Status: %s", findStatus(status));
1008 icqv5_cmd_send_msg(proto_tree* tree,
1014 proto_tree* subtree;
1016 int left = size; /* left chars to do */
1019 ti = proto_tree_add_text(tree,
1024 subtree = proto_item_add_subtree(ti, ett_icq_body);
1025 proto_tree_add_text(subtree, tvb,
1026 offset + CMD_SEND_MSG_RECV_UIN,
1029 tvb_get_letohl(tvb, offset + CMD_SEND_MSG_RECV_UIN));
1032 icqv5_decode_msgType(subtree,
1034 offset + CMD_SEND_MSG_MSG_TYPE,
1040 icqv5_cmd_login(proto_tree* tree,
1046 proto_tree* subtree;
1051 const u_char *ipAddrp;
1055 ti = proto_tree_add_text(tree,
1060 subtree = proto_item_add_subtree(ti, ett_icq_body);
1061 theTime = tvb_get_letohl(tvb, offset + CMD_LOGIN_TIME);
1062 aTime = ctime(&theTime);
1063 aTime[strlen(aTime)-1] = '\0';
1064 proto_tree_add_text(subtree, tvb,
1065 offset + CMD_LOGIN_TIME,
1067 "Time: %ld = %s", (long)theTime, aTime);
1068 port = tvb_get_letohl(tvb, offset + CMD_LOGIN_PORT);
1069 proto_tree_add_text(subtree, tvb,
1070 offset + CMD_LOGIN_PORT,
1073 passwdLen = tvb_get_letohs(tvb, offset + CMD_LOGIN_PASSLEN);
1074 proto_tree_add_text(subtree, tvb,
1075 offset + CMD_LOGIN_PASSLEN,
1079 tvb_get_ptr(tvb, offset + CMD_LOGIN_PASSWD,
1081 ipAddrp = tvb_get_ptr(tvb,
1082 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP,
1084 proto_tree_add_text(subtree, tvb,
1085 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP,
1087 "IP: %s", ip_to_str(ipAddrp));
1088 status = tvb_get_letohs(tvb,
1089 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS);
1090 proto_tree_add_text(subtree, tvb,
1091 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS,
1093 "Status: %s", findStatus(status));
1098 icqv5_cmd_contact_list(proto_tree* tree,
1103 proto_tree* subtree;
1110 ti = proto_tree_add_text(tree,
1115 subtree = proto_item_add_subtree(ti, ett_icq_body);
1116 num = tvb_get_guint8(tvb, offset + CMD_CONTACT_LIST_NUM);
1117 proto_tree_add_text(subtree, tvb,
1118 offset + CMD_CONTACT_LIST,
1120 "Number of uins: %u", num);
1122 * A sequence of num times UIN follows
1124 offset += (CMD_CONTACT_LIST_NUM + 1);
1125 for (i = 0; i < num; i++) {
1126 uin = tvb_get_letohl(tvb, offset);
1127 proto_tree_add_text(subtree, tvb,
1130 "UIN[%d]: %u", i ,uin);
1137 icqv5_cmd_no_params(proto_tree* tree, /* Tree to put the data in */
1138 tvbuff_t *tvb, /* Decrypted packet content */
1139 int offset, /* Offset from the start of the packet to the content */
1142 proto_tree* subtree;
1146 ti = proto_tree_add_text(tree,
1151 subtree = proto_item_add_subtree(ti, ett_icq_body);
1152 proto_tree_add_text(subtree, tvb,
1159 /**********************
1163 **********************
1166 icqv5_srv_no_params(proto_tree* tree, /* Tree to put the data in */
1167 tvbuff_t *tvb, /* Packet content */
1168 int offset, /* Offset from the start of the packet to the content */
1169 int size, /* Number of chars left to do */
1172 proto_tree* subtree;
1176 ti = proto_tree_add_text(tree,
1181 subtree = proto_item_add_subtree(ti, ett_icq_body);
1182 proto_tree_add_text(subtree, tvb,
1190 icqv5_srv_login_reply(proto_tree* tree,/* Tree to put the data in */
1191 tvbuff_t *tvb, /* Tvbuff with packet */
1192 int offset, /* Offset from the start of the packet to the content */
1193 int size) /* Number of chars left to do */
1195 proto_tree* subtree;
1197 const u_char *ipAddrp;
1200 ti = proto_tree_add_text(tree,
1203 SRV_LOGIN_REPLY_IP + 8,
1205 subtree = proto_item_add_subtree(ti, ett_icq_body);
1206 ipAddrp = tvb_get_ptr(tvb, offset + SRV_LOGIN_REPLY_IP, 4);
1207 proto_tree_add_text(subtree, tvb,
1208 offset + SRV_LOGIN_REPLY_IP,
1210 "IP: %s", ip_to_str(ipAddrp));
1215 icqv5_srv_user_online(proto_tree* tree,/* Tree to put the data in */
1216 tvbuff_t *tvb, /* Tvbuff with packet */
1217 int offset, /* Offset from the start of the packet to the content */
1218 int size) /* Number of chars left to do */
1220 proto_tree* subtree;
1222 const u_char *ipAddrp;
1223 const u_char *realipAddrp;
1227 ti = proto_tree_add_text(tree,
1230 SRV_LOGIN_REPLY_IP + 8,
1232 subtree = proto_item_add_subtree(ti, ett_icq_body);
1233 proto_tree_add_text(subtree, tvb,
1234 offset + SRV_USER_ONL_UIN,
1237 tvb_get_letohl(tvb, offset + SRV_USER_ONL_UIN));
1238 ipAddrp = tvb_get_ptr(tvb, offset + SRV_USER_ONL_IP, 4);
1239 proto_tree_add_text(subtree, tvb,
1240 offset + SRV_USER_ONL_IP,
1242 "IP: %s", ip_to_str(ipAddrp));
1243 proto_tree_add_text(subtree, tvb,
1244 offset + SRV_USER_ONL_PORT,
1247 tvb_get_letohl(tvb, offset + SRV_USER_ONL_PORT));
1248 realipAddrp = tvb_get_ptr(tvb, offset + SRV_USER_ONL_REALIP, 4);
1249 proto_tree_add_text(subtree, tvb,
1250 offset + SRV_USER_ONL_REALIP,
1252 "RealIP: %s", ip_to_str(realipAddrp));
1253 status = tvb_get_letohs(tvb, offset + SRV_USER_ONL_STATUS);
1254 proto_tree_add_text(subtree, tvb,
1255 offset + SRV_USER_ONL_STATUS,
1257 "Status: %s", findStatus(status));
1259 * Kojak: Hypothesis is that this field might be an encoding for the
1260 * version used by the UIN that changed. To test this, I included
1261 * this line to the code.
1263 proto_tree_add_text(subtree, tvb,
1264 offset + SRV_USER_ONL_X2,
1267 tvb_get_letohl(tvb, offset + SRV_USER_ONL_X2));
1272 icqv5_srv_user_offline(proto_tree* tree,/* Tree to put the data in */
1273 tvbuff_t *tvb, /* Tvbuff with packet */
1274 int offset, /* Offset from the start of the packet to the content */
1275 int size) /* Number of chars left to do */
1277 proto_tree* subtree;
1281 ti = proto_tree_add_text(tree,
1284 SRV_USER_OFFLINE_UIN + 4,
1286 subtree = proto_item_add_subtree(ti, ett_icq_body);
1287 proto_tree_add_text(subtree, tvb,
1288 offset + SRV_USER_OFFLINE_UIN,
1291 tvb_get_letohl(tvb, offset + SRV_USER_OFFLINE));
1296 icqv5_srv_multi(proto_tree* tree, /* Tree to put the data in */
1297 tvbuff_t *tvb, /* Packet content */
1298 int offset, /* Offset from the start of the packet to the content */
1299 int size, /* Number of chars left to do */
1302 proto_tree* subtree;
1309 ti = proto_tree_add_text(tree,
1314 subtree = proto_item_add_subtree(ti, ett_icq_body);
1315 num = tvb_get_guint8(tvb, offset + SRV_MULTI_NUM);
1316 proto_tree_add_text(subtree, tvb,
1317 offset + SRV_MULTI_NUM,
1319 "Number of pkts: %u", num);
1321 * A sequence of num times ( pktsize, packetData) follows
1323 offset += (SRV_MULTI_NUM + 1);
1324 for (i = 0; i < num; i++) {
1325 pktSz = tvb_get_letohs(tvb, offset);
1327 dissect_icqv5Server(tvb, offset, pinfo, subtree, pktSz);
1334 icqv5_srv_meta_user(proto_tree* tree, /* Tree to put the data in */
1335 tvbuff_t *tvb, /* Tvbuff with packet */
1336 int offset, /* Offset from the start of the packet to the content */
1337 int size) /* Number of chars left to do */
1340 proto_tree* subtree = NULL;
1342 proto_tree* sstree = NULL;
1343 proto_item* ti = NULL;
1346 unsigned char result;
1350 ti = proto_tree_add_text(tree,
1355 subtree = proto_item_add_subtree(ti, ett_icq_body);
1356 subcmd = tvb_get_letohs(tvb, offset + SRV_META_USER_SUBCMD);
1357 ti = proto_tree_add_text(subtree, tvb,
1358 offset + SRV_META_USER_SUBCMD,
1360 "%s", findSubCmd(subcmd));
1361 result = tvb_get_guint8(tvb, offset + SRV_META_USER_RESULT);
1362 proto_tree_add_text(subtree, tvb,
1363 offset + SRV_META_USER_RESULT,
1365 "%s", (result==0x0a)?"Success":"Failure");
1366 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1368 subcmd = tvb_get_letohs(tvb, offset + SRV_META_USER_SUBCMD);
1369 ti = proto_tree_add_text(tree, tvb,
1370 offset + SRV_META_USER_SUBCMD,
1372 "%s", findSubCmd(subcmd));
1373 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1374 result = tvb_get_guint8(tvb, offset + SRV_META_USER_RESULT);
1375 proto_tree_add_text(sstree, tvb,
1376 offset + SRV_META_USER_RESULT,
1378 "%s", (result==0x0a)?"Success":"Failure");
1381 /* Skip the META_USER header */
1386 case META_EX_USER_FOUND:
1388 /* This is almost the same as META_USER_FOUND,
1389 * however, there's an extra length field
1393 /* Read the length field */
1394 pktLen = tvb_get_letohs(tvb, offset);
1395 proto_tree_add_text(sstree, tvb,
1398 "Length: %u", pktLen);
1400 offset += sizeof(guint16); left -= sizeof(guint16);
1402 case META_USER_FOUND:
1404 /* The goto mentioned in this block should be local to this
1405 * block if C'd allow it.
1407 * They are used to "implement" a poorman's exception handling
1421 proto_tree_add_text(sstree, tvb,
1425 tvb_get_letohl(tvb, offset));
1426 offset+=sizeof(guint32);left-=sizeof(guint32);
1428 for ( ; *d!=NULL; d++) {
1429 len = proto_add_icq_attr(sstree,
1435 offset += len; left -= len;
1437 /* Get the authorize setting */
1438 auth = tvb_get_guint8(tvb, offset);
1439 proto_tree_add_text(sstree, tvb,
1442 "authorization: %s", (auth==0x01)?"Neccessary":"Who needs it");
1445 proto_tree_add_text(sstree, tvb,
1449 tvb_get_letohs(tvb, offset));
1450 offset+=sizeof(guint16);left-=sizeof(guint16);
1452 proto_tree_add_text(sstree, tvb,
1456 tvb_get_letohl(tvb, offset));
1457 offset+=sizeof(guint32);left-=sizeof(guint32);
1464 /* Get the about information */
1465 len = tvb_get_letohs(tvb, offset);
1466 offset+=sizeof(guint16);left-=sizeof(guint16);
1467 proto_tree_add_text(sstree, tvb,
1468 offset - sizeof(guint16),
1469 sizeof(guint16)+len,
1470 "About(%d): %.*s", len,
1471 len, tvb_get_ptr(tvb, offset, len));
1472 offset+=len;left-=len;
1475 case META_USER_INFO:
1477 /* The goto mentioned in this block should be local to this
1478 * block if C'd allow it.
1480 * They are used to "implement" a poorman's exception handling
1482 static const char* descr[] = {
1497 const char** d = descr;
1499 guint8 user_timezone;
1504 uin = tvb_get_letohl(tvb, offset);
1505 proto_tree_add_text(sstree, tvb,
1509 offset+=sizeof(guint32);left-=sizeof(guint32);
1513 * Get every field from the description
1515 while ((*d)!=NULL) {
1516 len = tvb_get_letohs(tvb, offset);
1517 offset+=sizeof(guint16);left-=sizeof(guint16);
1519 proto_tree_add_text(sstree, tvb,
1520 offset - sizeof(guint16),
1521 sizeof(guint16)+len,
1522 "%s(%d): %.*s",*d, len,
1524 tvb_get_ptr(tvb, offset, len - 1));
1525 offset+=len;left-=len;
1529 /* Get country code */
1530 country = tvb_get_letohs(tvb, offset);
1531 proto_tree_add_text(sstree, tvb,
1534 "Countrycode: %u", country);
1535 offset+=sizeof(guint16); left-=sizeof(guint16);
1536 /* Get the timezone setting */
1537 user_timezone = tvb_get_guint8(tvb, offset);
1538 proto_tree_add_text(sstree, tvb,
1540 sizeof(unsigned char),
1541 "Timezone: %u", user_timezone);
1543 /* Get the authorize setting */
1544 auth = tvb_get_guint8(tvb, offset);
1545 proto_tree_add_text(sstree, tvb,
1547 sizeof(unsigned char),
1548 "Authorization: (%u) %s",
1549 auth, (auth==0)?"No":"Yes");
1551 /* Get the webaware setting */
1552 auth = tvb_get_guint8(tvb, offset);
1553 proto_tree_add_text(sstree, tvb,
1555 sizeof(unsigned char),
1556 "Webaware: (%u) %s",
1557 auth, (auth==0)?"No":"Yes");
1559 /* Get the authorize setting */
1560 auth = tvb_get_guint8(tvb, offset);
1561 proto_tree_add_text(sstree, tvb,
1563 sizeof(unsigned char),
1565 auth, (auth==0)?"No":"Yes");
1570 /* This information is already printed in the tree */
1571 fprintf(stderr, "Meta subcmd: %04x\n", subcmd);
1578 icqv5_srv_recv_message(proto_tree* tree, /* Tree to put the data in */
1579 tvbuff_t* tvb, /* Packet content */
1580 int offset, /* Offset from the start of the packet to the content */
1581 int size) /* Number of chars left to do */
1583 proto_tree* subtree = NULL;
1584 proto_item* ti = NULL;
1593 ti = proto_tree_add_text(tree,
1598 subtree = proto_item_add_subtree(ti, ett_icq_body);
1599 proto_tree_add_item(subtree,
1602 offset + SRV_RECV_MSG_UIN,
1605 year = tvb_get_letohs(tvb, offset + SRV_RECV_MSG_YEAR);
1606 month = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_MONTH);
1607 day = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_DAY);
1608 hour = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_HOUR);
1609 minute = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_MINUTE);
1611 proto_tree_add_text(subtree, tvb,
1612 offset + SRV_RECV_MSG_YEAR,
1613 sizeof(guint16) + 4*sizeof(unsigned char),
1614 "Time: %u-%u-%u %02u:%02u",
1615 day, month, year, hour, minute);
1616 icqv5_decode_msgType(subtree,
1618 offset + SRV_RECV_MSG_MSG_TYPE,
1624 icqv5_srv_rand_user(proto_tree* tree, /* Tree to put the data in */
1625 tvbuff_t *tvb, /* Tvbuff with packet */
1626 int offset) /* Offset from the start of the packet to the content */
1628 proto_tree* subtree = NULL;
1629 proto_item* ti = NULL;
1631 const unsigned char* IP = NULL;
1633 const unsigned char* realIP = NULL;
1639 ti = proto_tree_add_text(tree,
1642 SRV_RAND_USER_TCP_VER + 2,
1644 subtree = proto_item_add_subtree(ti, ett_icq_body);
1646 uin = tvb_get_letohl(tvb, offset + SRV_RAND_USER_UIN);
1647 proto_tree_add_text(subtree, tvb,
1648 offset + SRV_RAND_USER_UIN,
1652 IP = tvb_get_ptr(tvb, offset + SRV_RAND_USER_IP, 4);
1653 proto_tree_add_text(subtree, tvb,
1654 offset + SRV_RAND_USER_IP,
1658 /* guint16 portNum */
1659 /* XXX - 16 bits, or 32 bits? */
1660 port = tvb_get_letohs(tvb, offset + SRV_RAND_USER_PORT);
1661 proto_tree_add_text(subtree, tvb,
1662 offset + SRV_RAND_USER_UIN,
1665 /* guint32 realIP */
1666 realIP = tvb_get_ptr(tvb, offset + SRV_RAND_USER_REAL_IP, 4);
1667 proto_tree_add_text(subtree, tvb,
1668 offset + SRV_RAND_USER_REAL_IP,
1670 "RealIP: %s", ip_to_str(realIP));
1671 /* guint8 Communication Class */
1672 commClass = tvb_get_guint8(tvb, offset + SRV_RAND_USER_CLASS);
1673 proto_tree_add_text(subtree, tvb,
1674 offset + SRV_RAND_USER_CLASS,
1676 "Class: %s", (commClass!=4)?"User to User":"Through Server");
1677 /* guint32 status */
1678 /* XXX - 16 bits, or 32 bits? */
1679 status = tvb_get_letohs(tvb, offset + SRV_RAND_USER_STATUS);
1680 proto_tree_add_text(subtree, tvb,
1681 offset + SRV_RAND_USER_STATUS,
1683 "Status: %s", findStatus(status));
1684 /* guint16 tcpVersion */
1685 tcpVer = tvb_get_letohs(tvb, offset + SRV_RAND_USER_TCP_VER);
1686 proto_tree_add_text(subtree, tvb,
1687 offset + SRV_RAND_USER_TCP_VER,
1689 "TCPVersion: %u", tcpVer);
1694 * Dissect all the v5 client traffic. This is encrypted, so be careful.
1697 dissect_icqv5Client(tvbuff_t *tvb,
1701 proto_tree *icq_tree = NULL;
1702 proto_tree *icq_header_tree = NULL;
1703 proto_item *ti = NULL;
1705 guint16 pktsize; /* The size of the ICQ content */
1706 guint32 rounded_size;
1709 guint8 *decr_pd; /* Decrypted content */
1712 pktsize = tvb_length(tvb);
1714 /* Get the encryption key */
1715 key = get_v5key(tvb, pktsize);
1718 * Make a copy of the packet data, and decrypt it.
1719 * The decryption processes 4 bytes at a time, and starts at
1720 * an offset of ICQ5_CL_SESSIONID (which isn't a multiple of 4),
1721 * so we make sure that there are
1723 * (ICQ5_CL_SESSIONID + a multiple of 4)
1725 * bytes in the buffer.
1727 rounded_size = ((((pktsize - ICQ5_CL_SESSIONID) + 3)/4)*4) + ICQ5_CL_SESSIONID;
1728 decr_pd = g_malloc(rounded_size);
1729 tvb_memcpy(tvb, decr_pd, 0, pktsize);
1730 decrypt_v5(decr_pd, rounded_size, key);
1732 /* Allocate a new tvbuff, referring to the decrypted data. */
1733 decr_tvb = tvb_new_real_data(decr_pd, pktsize, tvb_reported_length(tvb));
1735 /* Arrange that the allocated packet data copy be freed when the
1737 tvb_set_free_cb(decr_tvb, g_free);
1739 /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
1740 were handed refers, so it'll get cleaned up when that tvbuff
1742 tvb_set_child_real_data_tvbuff(tvb, decr_tvb);
1744 /* Add the decrypted data to the data source list. */
1745 add_new_data_source(pinfo->fd, decr_tvb, "Decrypted");
1747 cmd = tvb_get_letohs(decr_tvb, ICQ5_CL_CMD);
1749 if (check_col(pinfo->cinfo, COL_INFO))
1750 col_add_fstr(pinfo->cinfo, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
1753 ti = proto_tree_add_protocol_format(tree,
1758 "ICQv5 %s (len %u)",
1761 icq_tree = proto_item_add_subtree(ti, ett_icq);
1762 ti = proto_tree_add_uint_format(icq_tree,
1769 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
1771 proto_tree_add_text(icq_header_tree, tvb,
1775 tvb_get_letohs(tvb, ICQ_VERSION));
1776 proto_tree_add_item(icq_header_tree,
1782 proto_tree_add_item(icq_header_tree,
1788 proto_tree_add_uint_format(icq_header_tree,
1795 val_to_str(cmd, clientCmdCode, "Unknown"), cmd);
1796 proto_tree_add_text(icq_header_tree, decr_tvb,
1799 "Seq Number 1: 0x%04x",
1800 tvb_get_letohs(decr_tvb, ICQ5_CL_SEQNUM1));
1801 proto_tree_add_text(icq_header_tree, decr_tvb,
1804 "Seq Number 2: 0x%04x",
1805 tvb_get_letohs(decr_tvb, ICQ5_CL_SEQNUM2));
1806 proto_tree_add_uint_format(icq_header_tree,
1816 icqv5_cmd_ack(icq_tree,
1821 case CMD_MSG_TO_NEW_USER:
1822 icqv5_cmd_send_msg(icq_tree,
1825 pktsize - ICQ5_CL_HDRSIZE,
1828 case CMD_RAND_SEARCH:
1829 icqv5_cmd_rand_search(icq_tree,
1832 pktsize - ICQ5_CL_HDRSIZE);
1835 icqv5_cmd_login(icq_tree,
1838 pktsize - ICQ5_CL_HDRSIZE);
1840 case CMD_SEND_TEXT_CODE:
1841 icqv5_cmd_send_text_code(icq_tree,
1844 pktsize - ICQ5_CL_HDRSIZE);
1846 case CMD_STATUS_CHANGE:
1847 icqv5_cmd_status_change(icq_tree,
1851 case CMD_ACK_MESSAGES:
1852 icqv5_cmd_ack_messages(icq_tree,
1856 case CMD_KEEP_ALIVE:
1857 icqv5_cmd_keep_alive(icq_tree,
1861 case CMD_ADD_TO_LIST:
1862 icqv5_cmd_add_to_list(icq_tree,
1866 case CMD_CONTACT_LIST:
1867 icqv5_cmd_contact_list(icq_tree,
1870 pktsize - ICQ5_CL_HDRSIZE);
1873 case CMD_REG_NEW_USER:
1874 case CMD_QUERY_SERVERS:
1875 case CMD_QUERY_ADDONS:
1876 icqv5_cmd_no_params(icq_tree,
1882 proto_tree_add_text(icq_tree,
1885 pktsize - ICQ5_CL_HDRSIZE,
1887 fprintf(stderr,"Missing: %s\n", findClientCmd(cmd));
1894 dissect_icqv5Server(tvbuff_t *tvb,
1900 /* Server traffic is easy, not encrypted */
1901 proto_tree *icq_tree = NULL;
1902 proto_tree *icq_header_tree = NULL;
1903 proto_item *ti = NULL;
1904 int changeCol = (pktsize==-1);
1908 cmd = tvb_get_letohs(tvb, offset + ICQ5_SRV_CMD);
1909 if (changeCol && check_col(pinfo->cinfo, COL_INFO))
1910 col_add_fstr(pinfo->cinfo, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
1913 pktsize = tvb_reported_length(tvb);
1916 ti = proto_tree_add_protocol_format(tree,
1921 "ICQv5 %s (len %u)",
1925 icq_tree = proto_item_add_subtree(ti, ett_icq);
1927 ti = proto_tree_add_uint_format(icq_tree,
1934 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
1936 proto_tree_add_text(icq_header_tree, tvb,
1937 offset + ICQ_VERSION,
1940 tvb_get_letohs(tvb, ICQ_VERSION));
1941 proto_tree_add_item(icq_header_tree,
1944 offset + ICQ5_SRV_SESSIONID,
1947 proto_tree_add_uint_format(icq_header_tree,
1950 offset + ICQ5_SRV_CMD,
1954 val_to_str(cmd, serverCmdCode, "Unknown"), cmd);
1955 proto_tree_add_text(icq_header_tree, tvb,
1956 offset + ICQ5_SRV_SEQNUM1,
1958 "Seq Number 1: 0x%04x",
1959 tvb_get_letohs(tvb, offset + ICQ5_SRV_SEQNUM1));
1960 proto_tree_add_text(icq_header_tree, tvb,
1961 offset + ICQ5_SRV_SEQNUM2,
1963 "Seq Number 2: 0x%04x",
1964 tvb_get_letohs(tvb, offset + ICQ5_SRV_SEQNUM2));
1965 proto_tree_add_item(icq_header_tree,
1968 offset + ICQ5_SRV_UIN,
1971 proto_tree_add_item(icq_header_tree,
1974 offset + ICQ5_SRV_CHECKCODE,
1979 icqv5_srv_rand_user(icq_tree,
1981 offset + ICQ5_SRV_HDRSIZE);
1983 case SRV_SYS_DELIVERED_MESS:
1984 /* The message structures are all the same. Why not run
1985 * the same routine? */
1986 icqv5_cmd_send_msg(icq_tree,
1988 offset + ICQ5_SRV_HDRSIZE,
1989 pktsize - ICQ5_SRV_HDRSIZE,
1992 case SRV_USER_ONLINE:
1993 icqv5_srv_user_online(icq_tree,
1995 offset + ICQ5_SRV_HDRSIZE,
1996 pktsize - ICQ5_SRV_HDRSIZE);
1998 case SRV_USER_OFFLINE:
1999 icqv5_srv_user_offline(icq_tree,
2001 offset + ICQ5_SRV_HDRSIZE,
2002 pktsize - ICQ5_SRV_HDRSIZE);
2004 case SRV_LOGIN_REPLY:
2005 icqv5_srv_login_reply(icq_tree,
2007 offset + ICQ5_SRV_HDRSIZE,
2008 pktsize - ICQ5_SRV_HDRSIZE);
2011 icqv5_srv_meta_user(icq_tree,
2013 offset + ICQ5_SRV_HDRSIZE,
2014 pktsize - ICQ5_SRV_HDRSIZE);
2016 case SRV_RECV_MESSAGE:
2017 icqv5_srv_recv_message(icq_tree,
2019 offset + ICQ5_SRV_HDRSIZE,
2020 pktsize - ICQ5_SRV_HDRSIZE);
2023 icqv5_srv_multi(icq_tree,
2025 offset + ICQ5_SRV_HDRSIZE,
2026 pktsize - ICQ5_SRV_HDRSIZE,
2030 case SRV_SILENT_TOO_LONG:
2034 case SRV_UPDATE_SUCCESS:
2035 icqv5_srv_no_params(icq_tree,
2037 offset + ICQ5_SRV_HDRSIZE,
2038 pktsize - ICQ5_SRV_HDRSIZE,
2042 proto_tree_add_text(icq_tree,
2044 offset + ICQ5_SRV_HDRSIZE,
2045 pktsize - ICQ5_SRV_HDRSIZE,
2047 fprintf(stderr,"Missing: %s\n", findServerCmd(cmd));
2053 static void dissect_icqv5(tvbuff_t *tvb,
2059 if (check_col(pinfo->cinfo, COL_PROTOCOL))
2060 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQv5 (UDP)");
2061 if (check_col(pinfo->cinfo, COL_INFO))
2062 col_set_str(pinfo->cinfo, COL_INFO, "ICQv5 packet");
2064 unknown = tvb_get_letohl(tvb, ICQ5_UNKNOWN);
2066 if (unknown == 0x0L) {
2067 dissect_icqv5Client(tvb, pinfo, tree);
2069 dissect_icqv5Server(tvb, 0, pinfo, tree, -1);
2073 static void dissect_icq(tvbuff_t *tvb,
2079 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
2080 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQ");
2082 if (check_col(pinfo->cinfo, COL_INFO)) {
2083 col_clear(pinfo->cinfo, COL_INFO);
2086 version = tvb_get_letohs(tvb, ICQ_VERSION);
2089 dissect_icqv5(tvb, pinfo, tree);
2092 dissect_icqv4(tvb, pinfo, tree);
2095 dissect_icqv3(tvb, pinfo, tree);
2098 dissect_icqv2(tvb, pinfo, tree);
2101 fprintf(stderr, "ICQ: Unknown version (%d)\n", version);
2106 /* registration with the filtering engine */
2108 proto_register_icq(void)
2110 static hf_register_info hf[] = {
2112 {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2114 {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2115 { &hf_icq_sessionid,
2116 {"Session ID", "icq.sessionid", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2117 { &hf_icq_client_cmd,
2118 {"Client command", "icq.client_cmd", FT_UINT16, BASE_HEX, VALS(clientCmdCode), 0x0, "", HFILL }},
2119 { &hf_icq_server_cmd,
2120 {"Server command", "icq.server_cmd", FT_UINT16, BASE_DEC, VALS(serverCmdCode), 0x0, "", HFILL }},
2121 { &hf_icq_checkcode,
2122 {"Checkcode", "icq.checkcode", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2124 {"Decode", "icq.decode", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}
2126 static gint *ett[] = {
2131 &ett_icq_body_parts,
2134 proto_icq = proto_register_protocol("ICQ Protocol", "ICQ", "icq");
2136 proto_register_field_array(proto_icq, hf, array_length(hf));
2138 proto_register_subtree_array(ett, array_length(ett));
2142 proto_reg_handoff_icq(void)
2144 dissector_handle_t icq_handle;
2146 icq_handle = create_dissector_handle(dissect_icq, proto_icq);
2147 dissector_add("udp.port", UDP_PORT_ICQ, icq_handle);