2 * Routines for ICQ packet disassembly
4 * $Id: packet-icq.c,v 1.48 2002/08/28 21:00:17 jmayer 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.
48 #include <epan/packet.h>
49 #include <epan/resolv.h>
51 static int proto_icq = -1;
52 static int hf_icq_uin = -1;
53 static int hf_icq_client_cmd = -1;
54 static int hf_icq_server_cmd = -1;
55 static int hf_icq_sessionid = -1;
56 static int hf_icq_checkcode = -1;
57 static int hf_icq_decode = -1;
58 static int hf_icq_type = -1;
60 static gint ett_icq = -1;
61 static gint ett_icq_header = -1;
62 static gint ett_icq_decode = -1;
63 static gint ett_icq_body = -1;
64 static gint ett_icq_body_parts = -1;
66 #define UDP_PORT_ICQ 4000
68 enum { ICQ5_client, ICQ5_server};
70 static void dissect_icqv5(tvbuff_t *tvb,
75 dissect_icqv5Server(tvbuff_t *tvb,
81 /* Offsets of fields in the ICQ headers */
82 /* Can be 0x0002 or 0x0005 */
83 #define ICQ_VERSION 0x00
84 /* Is either one (server) or four (client) bytes long */
85 /* Client header offsets */
86 #define ICQ5_UNKNOWN 0x02
87 #define ICQ5_CL_UIN 0x06
88 #define ICQ5_CL_SESSIONID 0x0a
89 #define ICQ5_CL_CMD 0x0e
90 #define ICQ5_CL_SEQNUM1 0x10
91 #define ICQ5_CL_SEQNUM2 0x12
92 #define ICQ5_CL_CHECKCODE 0x14
93 #define ICQ5_CL_PARAM 0x18
94 #define ICQ5_CL_HDRSIZE 0x18
96 /* Server header offsets */
97 #define ICQ5_SRV_SESSIONID 0x03
98 #define ICQ5_SRV_CMD 0x07
99 #define ICQ5_SRV_SEQNUM1 0x09
100 #define ICQ5_SRV_SEQNUM2 0x0b
101 #define ICQ5_SRV_UIN 0x0d
102 #define ICQ5_SRV_CHECKCODE 0x11
103 #define ICQ5_SRV_PARAM 0x15
104 #define ICQ5_SRV_HDRSIZE 0x15
106 #define SRV_ACK 0x000a
108 #define SRV_SILENT_TOO_LONG 0x001e
110 #define SRV_GO_AWAY 0x0028
112 #define SRV_NEW_UIN 0x0046
114 /* LOGIN_REPLY is very scary. It has a lot of fields that are undocumented
115 * Only the IP field makes sense */
116 #define SRV_LOGIN_REPLY 0x005a
117 #define SRV_LOGIN_REPLY_IP 0x000c
119 #define SRV_BAD_PASS 0x0064
121 #define SRV_USER_ONLINE 0x006e
122 #define SRV_USER_ONL_UIN 0x0000
123 #define SRV_USER_ONL_IP 0x0004
124 #define SRV_USER_ONL_PORT 0x0008
125 #define SRV_USER_ONL_REALIP 0x000c
126 #define SRV_USER_ONL_X1 0x0010
127 #define SRV_USER_ONL_STATUS 0x0013
128 #define SRV_USER_ONL_X2 0x0015
130 #define SRV_USER_OFFLINE 0x0078
131 #define SRV_USER_OFFLINE_UIN 0x0000
133 #define SRV_MULTI 0x0212
134 #define SRV_MULTI_NUM 0x0000
136 #define SRV_META_USER 0x03de
137 #define SRV_META_USER_SUBCMD 0x0000
138 #define SRV_META_USER_RESULT 0x0002
139 #define SRV_META_USER_DATA 0x0003
141 #define SRV_UPDATE_SUCCESS 0x01e0
143 #define SRV_UPDATE_FAIL 0x01ea
146 * ICQv5 SRV_META_USER subcommands
148 #define META_EX_USER_FOUND 0x0190
149 #define META_USER_FOUND 0x019a
150 #define META_ABOUT 0x00e6
151 #define META_USER_INFO 0x00c8
153 #define SRV_RECV_MESSAGE 0x00dc
154 #define SRV_RECV_MSG_UIN 0x0000
155 #define SRV_RECV_MSG_YEAR 0x0004
156 #define SRV_RECV_MSG_MONTH 0x0006
157 #define SRV_RECV_MSG_DAY 0x0007
158 #define SRV_RECV_MSG_HOUR 0x0008
159 #define SRV_RECV_MSG_MINUTE 0x0009
160 #define SRV_RECV_MSG_MSG_TYPE 0x000a
162 #define SRV_RAND_USER 0x024e
163 #define SRV_RAND_USER_UIN 0x0000
164 #define SRV_RAND_USER_IP 0x0004
165 #define SRV_RAND_USER_PORT 0x0008
166 #define SRV_RAND_USER_REAL_IP 0x000c
167 #define SRV_RAND_USER_CLASS 0x0010
168 #define SRV_RAND_USER_X1 0x0011
169 #define SRV_RAND_USER_STATUS 0x0015
170 #define SRV_RAND_USER_TCP_VER 0x0019
172 /* This message has the same structure as cmd_send_msg */
173 #define SRV_SYS_DELIVERED_MESS 0x0104
175 static const value_string serverMetaSubCmdCode[] = {
176 { META_USER_FOUND, "META_USER_FOUND" },
177 { META_EX_USER_FOUND, "META_EX_USER_FOUND" },
178 { META_ABOUT, "META_ABOUT" },
179 { META_USER_INFO, "META_USER_INFO" },
183 static const value_string serverCmdCode[] = {
184 { SRV_ACK, "SRV_ACK" },
185 { SRV_SILENT_TOO_LONG, "SRV_SILENT_TOO_LONG" },
186 { SRV_GO_AWAY, "SRV_GO_AWAY" },
187 { SRV_NEW_UIN, "SRV_NEW_UIN" },
188 { SRV_LOGIN_REPLY, "SRV_LOGIN_REPLY" },
189 { SRV_BAD_PASS, "SRV_BAD_PASS" },
190 { SRV_USER_ONLINE, "SRV_USER_ONLINE" },
191 { SRV_USER_OFFLINE, "SRV_USER_OFFLINE" },
192 { 130, "SRV_QUERY" },
193 { 140, "SRV_USER_FOUND" },
194 { 160, "SRV_END_OF_SEARCH" },
195 { 180, "SRV_NEW_USER" },
196 { 200, "SRV_UPDATE_EXT" },
197 { SRV_RECV_MESSAGE, "SRV_RECV_MESSAGE" },
198 { 230, "SRV_END_OFFLINE_MESSAGES" },
199 { 240, "SRV_NOT_CONNECTED" },
200 { 250, "SRV_TRY_AGAIN" },
201 { SRV_SYS_DELIVERED_MESS, "SRV_SYS_DELIVERED_MESS" },
202 { 280, "SRV_INFO_REPLY" },
203 { 290, "SRV_EXT_INFO_REPLY" },
204 { 420, "SRV_STATUS_UPDATE" },
205 { 450, "SRV_SYSTEM_MESSAGE" },
206 { SRV_UPDATE_SUCCESS, "SRV_UPDATE_SUCCESS" },
207 { SRV_UPDATE_FAIL, "SRV_UPDATE_FAIL" },
208 { 500, "SRV_AUTH_UPDATE" },
209 { SRV_MULTI, "SRV_MULTI_PACKET" },
210 { 540, "SRV_END_CONTACTLIST_STATUS" },
211 { SRV_RAND_USER, "SRV_RAND_USER" },
212 { SRV_META_USER, "SRV_META_USER" },
216 #define MSG_TEXT 0x0001
217 #define MSG_URL 0x0004
218 #define MSG_AUTH_REQ 0x0006
219 #define MSG_AUTH 0x0008
220 #define MSG_USER_ADDED 0x000c
221 #define MSG_EMAIL 0x000e
222 #define MSG_CONTACTS 0x0013
224 #define STATUS_ONLINE 0x00000000
225 #define STATUS_AWAY 0x00000001
226 #define STATUS_DND 0x00000013
227 #define STATUS_INVISIBLE 0x00000100
228 #define STATUS_OCCUPIED 0x00000010
229 #define STATUS_NA 0x00000004
230 #define STATUS_CHAT 0x00000020
232 /* Offsets for all packets measured from the start of the payload; i.e.
233 * with the ICQ header removed
235 #define CMD_ACK 0x000a
236 #define CMD_ACK_RANDOM 0x0000
238 #define CMD_SEND_MSG 0x010E
239 #define CMD_SEND_MSG_RECV_UIN 0x0000
240 #define CMD_SEND_MSG_MSG_TYPE 0x0004
241 #define CMD_SEND_MSG_MSG_LEN 0x0006
242 #define CMD_SEND_MSG_MSG_TEXT 0x0008
243 /* The rest of the packet should be a null-term string */
245 #define CMD_LOGIN 0x03E8
246 #define CMD_LOGIN_TIME 0x0000
247 #define CMD_LOGIN_PORT 0x0004
248 #define CMD_LOGIN_PASSLEN 0x0008
249 #define CMD_LOGIN_PASSWD 0x000A
250 /* The password is variable length; so when we've decoded the passwd,
251 * the structure starts counting at 0 again.
253 #define CMD_LOGIN_IP 0x0004
254 #define CMD_LOGIN_STATUS 0x0009
256 #define CMD_CONTACT_LIST 0x0406
257 #define CMD_CONTACT_LIST_NUM 0x0000
259 #define CMD_USER_META 0x064a
261 #define CMD_REG_NEW_USER 0x03fc
263 #define CMD_ACK_MESSAGES 0x0442
264 #define CMD_ACK_MESSAGES_RANDOM 0x0000
266 #define CMD_KEEP_ALIVE 0x042e
267 #define CMD_KEEP_ALIVE_RANDOM 0x0000
269 #define CMD_SEND_TEXT_CODE 0x0438
270 #define CMD_SEND_TEXT_CODE_LEN 0x0000
271 #define CMD_SEND_TEXT_CODE_TEXT 0x0002
273 #define CMD_MSG_TO_NEW_USER 0x0456
275 #define CMD_QUERY_SERVERS 0x04ba
277 #define CMD_QUERY_ADDONS 0x04c4
279 #define CMD_STATUS_CHANGE 0x04d8
280 #define CMD_STATUS_CHANGE_STATUS 0x0000
282 #define CMD_ADD_TO_LIST 0x053c
283 #define CMD_ADD_TO_LIST_UIN 0x0000
285 #define CMD_RAND_SEARCH 0x056e
286 #define CMD_RAND_SEARCH_GROUP 0x0000
288 #define CMD_META_USER 0x064a
290 static const value_string msgTypeCode[] = {
291 { MSG_TEXT, "MSG_TEXT" },
292 { MSG_URL, "MSG_URL" },
293 { MSG_AUTH_REQ, "MSG_AUTH_REQ" },
294 { MSG_AUTH, "MSG_AUTH" },
295 { MSG_USER_ADDED, "MSG_USER_ADDED" },
296 { MSG_EMAIL, "MSG_EMAIL" },
297 { MSG_CONTACTS, "MSG_CONTACTS" },
301 static const value_string statusCode[] = {
302 { STATUS_ONLINE, "ONLINE" },
303 { STATUS_AWAY, "AWAY" },
304 { STATUS_DND, "DND" },
305 { STATUS_INVISIBLE, "INVISIBLE" },
306 { STATUS_OCCUPIED, "OCCUPIED" },
308 { STATUS_CHAT, "Free for Chat" },
312 static const value_string clientCmdCode[] = {
313 { CMD_ACK, "CMD_ACK" },
314 { CMD_SEND_MSG, "CMD_SEND_MESSAGE" },
315 { CMD_LOGIN, "CMD_LOGIN" },
316 { CMD_REG_NEW_USER, "CMD_REG_NEW_USER" },
317 { 1030, "CMD_CONTACT_LIST" },
318 { 1050, "CMD_SEARCH_UIN" },
319 { 1060, "CMD_SEARCH_USER" },
320 { 1070, "CMD_KEEP_ALIVE" },
321 { CMD_SEND_TEXT_CODE, "CMD_SEND_TEXT_CODE" },
322 { CMD_ACK_MESSAGES, "CMD_ACK_MESSAGES" },
323 { 1100, "CMD_LOGIN_1" },
324 { CMD_MSG_TO_NEW_USER, "CMD_MSG_TO_NEW_USER" },
325 { 1120, "CMD_INFO_REQ" },
326 { 1130, "CMD_EXT_INFO_REQ" },
327 { 1180, "CMD_CHANGE_PW" },
328 { 1190, "CMD_NEW_USER_INFO" },
329 { 1200, "CMD_UPDATE_EXT_INFO" },
330 { CMD_QUERY_SERVERS, "CMD_QUERY_SERVERS" },
331 { CMD_QUERY_ADDONS, "CMD_QUERY_ADDONS" },
332 { CMD_STATUS_CHANGE, "CMD_STATUS_CHANGE" },
333 { 1260, "CMD_NEW_USER_1" },
334 { 1290, "CMD_UPDATE_INFO" },
335 { 1300, "CMD_AUTH_UPDATE" },
336 { 1310, "CMD_KEEP_ALIVE2" },
337 { 1320, "CMD_LOGIN_2" },
338 { CMD_ADD_TO_LIST, "CMD_ADD_TO_LIST" },
339 { 1380, "CMD_RAND_SET" },
340 { CMD_RAND_SEARCH, "CMD_RAND_SEARCH" },
341 { CMD_META_USER, "CMD_META_USER" },
342 { 1700, "CMD_INVIS_LIST" },
343 { 1710, "CMD_VIS_LIST" },
344 { 1720, "CMD_UPDATE_LIST" },
349 * All ICQv5 decryption code thanx to Sebastien Dault (daus01@gel.usherb.ca)
353 0x59, 0x60, 0x37, 0x6B, 0x65, 0x62, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x60, 0x57, 0x5B, 0x3D,
354 0x5E, 0x34, 0x6D, 0x36, 0x50, 0x3F, 0x6F, 0x67, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x47, 0x63, 0x39,
355 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x43, 0x69, 0x48, 0x33, 0x31, 0x64, 0x35, 0x5A, 0x4A, 0x42,
356 0x56, 0x40, 0x67, 0x53, 0x41, 0x07, 0x6C, 0x49, 0x58, 0x3B, 0x4D, 0x46, 0x68, 0x43, 0x69, 0x48,
357 0x33, 0x31, 0x44, 0x65, 0x62, 0x46, 0x48, 0x53, 0x41, 0x07, 0x6C, 0x69, 0x48, 0x33, 0x51, 0x54,
358 0x5D, 0x4E, 0x6C, 0x49, 0x38, 0x4B, 0x55, 0x4A, 0x62, 0x46, 0x48, 0x33, 0x51, 0x34, 0x6D, 0x36,
359 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x63, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64, 0x35, 0x5A,
360 0x6A, 0x52, 0x6E, 0x3C, 0x51, 0x34, 0x6D, 0x36, 0x50, 0x5F, 0x5F, 0x3F, 0x4F, 0x37, 0x4B, 0x35,
361 0x5A, 0x4A, 0x62, 0x66, 0x58, 0x3B, 0x4D, 0x66, 0x58, 0x5B, 0x5D, 0x4E, 0x6C, 0x49, 0x58, 0x3B,
362 0x4D, 0x66, 0x58, 0x3B, 0x4D, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64,
363 0x55, 0x6A, 0x32, 0x3E, 0x44, 0x45, 0x52, 0x6E, 0x3C, 0x31, 0x64, 0x55, 0x6A, 0x52, 0x4E, 0x6C,
364 0x69, 0x48, 0x53, 0x61, 0x4C, 0x39, 0x30, 0x6F, 0x47, 0x63, 0x59, 0x60, 0x57, 0x5B, 0x3D, 0x3E,
365 0x64, 0x35, 0x3A, 0x3A, 0x5A, 0x6A, 0x52, 0x4E, 0x6C, 0x69, 0x48, 0x53, 0x61, 0x6C, 0x49, 0x58,
366 0x3B, 0x4D, 0x46, 0x68, 0x63, 0x39, 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x67, 0x53, 0x41, 0x25, 0x41,
367 0x3C, 0x51, 0x54, 0x3D, 0x5E, 0x54, 0x5D, 0x4E, 0x4C, 0x39, 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F,
368 0x47, 0x43, 0x69, 0x48, 0x33, 0x51, 0x54, 0x5D, 0x6E, 0x3C, 0x31, 0x64, 0x35, 0x5A, 0x00, 0x00 };
373 return val_to_str(num, msgTypeCode, "Unknown");
379 return val_to_str(num, serverMetaSubCmdCode, "Unknown (0x%04x)");
383 findClientCmd(int num)
385 return val_to_str(num, clientCmdCode, "Unknown (%u)");
389 findServerCmd(int num)
391 return val_to_str(num, serverCmdCode, "Unknown (%u)");
397 return val_to_str(num, statusCode, "Unknown (0x%08x)");
401 get_v5key(tvbuff_t *tvb, int len)
403 guint32 a1, a2, a3, a4, a5;
404 guint32 code, check, key;
406 code = tvb_get_letohl(tvb, ICQ5_CL_CHECKCODE);
408 a1 = code & 0x0001f000;
409 a2 = code & 0x07c007c0;
410 a3 = code & 0x003e0001;
411 a4 = code & 0xf8000000;
412 a5 = code & 0x0000083e;
420 check = a5 + a1 + a2 + a3 + a4;
421 key = len * 0x68656C6C;
427 decrypt_v5(guchar *bfr, guint32 size,guint32 key)
432 for (i=ICQ5_CL_SESSIONID; i < size; i+=4 ) {
433 k = key+table_v5[i&0xff];
435 bfr[i] ^= (guchar)(k & 0xff);
436 bfr[i+1] ^= (guchar)((k & 0xff00)>>8);
439 bfr[i+2] ^= (guchar)((k & 0xff0000)>>16);
440 bfr[i+3] ^= (guchar)((k & 0xff000000)>>24);
446 dissect_icqv4(tvbuff_t *tvb,
450 proto_tree *icq_tree = NULL;
451 proto_item *ti = NULL;
453 /* Not really implemented yet */
454 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
455 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQv4 (UDP)");
457 if (check_col(pinfo->cinfo, COL_INFO)) {
458 col_set_str(pinfo->cinfo, COL_INFO, "ICQ Version 4 protocol");
461 ti = proto_tree_add_protocol_format(tree,
467 icq_tree = proto_item_add_subtree(ti, ett_icq);
469 proto_tree_add_text(icq_tree, tvb,
473 tvb_get_letohs(tvb, ICQ_VERSION));
478 dissect_icqv3(tvbuff_t *tvb,
482 proto_tree *icq_tree = NULL;
483 proto_item *ti = NULL;
485 /* Not really implemented yet */
486 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
487 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQv3 (UDP)");
489 if (check_col(pinfo->cinfo, COL_INFO)) {
490 col_set_str(pinfo->cinfo, COL_INFO, "ICQ Version 3 protocol");
493 ti = proto_tree_add_protocol_format(tree,
499 icq_tree = proto_item_add_subtree(ti, ett_icq);
501 proto_tree_add_text(icq_tree, tvb,
505 tvb_get_letohs(tvb, ICQ_VERSION));
510 dissect_icqv2(tvbuff_t *tvb,
514 proto_tree *icq_tree = NULL;
515 proto_item *ti = NULL;
517 /* Not really implemented yet */
518 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
519 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQv2 (UDP)");
521 if (check_col(pinfo->cinfo, COL_INFO)) {
522 col_set_str(pinfo->cinfo, COL_INFO, "ICQ Version 2 protocol");
525 ti = proto_tree_add_protocol_format(tree,
531 icq_tree = proto_item_add_subtree(ti, ett_icq);
533 proto_tree_add_text(icq_tree, tvb,
537 tvb_get_letohs(tvb, ICQ_VERSION));
542 * The packet has, at offset "offset" a (len, string) pair.
543 * Display the length and string in the tree.
545 * If anything is wrong, return -1, since -1 is not a valid string
546 * length. Else, return the number of chars processed.
549 proto_add_icq_attr(proto_tree* tree, /* The tree to add to */
550 tvbuff_t *tvb, /* Tvbuff with packet */
551 const int offset, /* Offset from the start of packet of field */
552 char* descr) /* The description to use in the tree */
556 len = tvb_get_letohs(tvb, offset);
557 if (len > tvb_reported_length_remaining(tvb, offset))
558 return -1; /* length goes past end of packet */
559 proto_tree_add_text(tree, tvb,
561 sizeof(guint16) + len,
562 "%s[%u]: %.*s", descr, len, len,
563 tvb_get_ptr(tvb, offset + sizeof(guint16), len));
564 return len + sizeof(guint16);
568 icqv5_decode_msgType(proto_tree* tree,
573 proto_item* ti = NULL;
574 proto_tree* subtree = NULL;
578 int sz; /* Size of the current element */
580 static char* url_field_descr[] = {
584 #define N_URL_FIELDS (sizeof url_field_descr / sizeof url_field_descr[0])
585 static char* email_field_descr[] = {
593 #define N_EMAIL_FIELDS (sizeof email_field_descr / sizeof email_field_descr[0])
594 static char* auth_req_field_descr[] = {
602 #define N_AUTH_REQ_FIELDS (sizeof auth_req_field_descr / sizeof auth_req_field_descr[0])
603 static char* user_added_field_descr[] = {
609 #define N_USER_ADDED_FIELDS (sizeof user_added_field_descr / sizeof user_added_field_descr[0])
611 msgType = tvb_get_letohs(tvb, offset);
612 ti = proto_tree_add_text(tree, tvb,
615 "Message: Type = %u (%s)", msgType, findMsgType(msgType));
616 /* Create a new subtree */
617 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
619 proto_tree_add_text(subtree, tvb,
622 "Type: %u (%s)", msgType, findMsgType(msgType));
625 if (msgType != MSG_AUTH) {
627 * XXX - does a MSG_AUTH message really have 3 bytes of information
628 * rather than a length field?
630 proto_tree_add_text(subtree, tvb,
634 tvb_get_letohs(tvb, offset));
640 case 0xffff: /* Field unknown */
643 fprintf(stderr, "Unknown msgType: %u (%04x)\n", msgType, msgType);
646 proto_tree_add_text(subtree, tvb,
650 tvb_get_ptr(tvb, offset, left));
653 for (n = 0; n < N_URL_FIELDS; n++) {
654 if (n != N_URL_FIELDS - 1) {
655 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
656 sz = sep_offset - offset + 1;
660 proto_tree_add_text(subtree, tvb,
666 tvb_get_ptr(tvb, offset, sz));
668 proto_tree_add_text(subtree, tvb,
671 "%s: %s", url_field_descr[n], "(empty)");
678 for (n = 0; n < N_EMAIL_FIELDS; n++) {
679 if (n != N_EMAIL_FIELDS - 1) {
680 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
681 sz = sep_offset - offset + 1;
685 proto_tree_add_text(subtree, tvb,
689 email_field_descr[n],
691 tvb_get_ptr(tvb, offset, sz));
693 proto_tree_add_text(subtree, tvb,
696 "%s: %s", email_field_descr[n], "(empty)");
705 /* Three bytes, first is a char signifying success */
706 unsigned char auth_suc;
708 auth_suc = tvb_get_guint8(tvb, offset);
709 proto_tree_add_text(subtree, tvb,
712 "Authorization: (%u) %s",auth_suc,
713 (auth_suc==0)?"Denied":"Allowed");
715 proto_tree_add_text(subtree, tvb,
719 tvb_get_letohs(tvb, offset));
723 for (n = 0; n < N_AUTH_REQ_FIELDS; n++) {
724 if (n != N_AUTH_REQ_FIELDS - 1) {
725 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
726 sz = sep_offset - offset + 1;
730 proto_tree_add_text(subtree, tvb,
734 auth_req_field_descr[n],
736 tvb_get_ptr(tvb, offset, sz));
738 proto_tree_add_text(subtree, tvb,
741 "%s: %s", auth_req_field_descr[n], "(empty)");
748 for (n = 0; n < N_USER_ADDED_FIELDS; n++) {
749 if (n != N_USER_ADDED_FIELDS - 1) {
750 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
751 sz = sep_offset - offset + 1;
755 proto_tree_add_text(subtree, tvb,
759 user_added_field_descr[n],
761 tvb_get_ptr(tvb, offset, sz));
763 proto_tree_add_text(subtree, tvb,
766 "%s: %s", user_added_field_descr[n], "(empty)");
774 gint sep_offset_prev;
775 int sz = 0; /* Size of the current element */
776 int n = 0; /* The nth element */
777 gboolean last = FALSE;
780 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
781 if (sep_offset != -1)
782 sz = sep_offset - offset + 1;
788 /* The first element is the number of Nick/UIN pairs follow */
789 proto_tree_add_text(subtree, tvb,
792 "Number of pairs: %.*s",
794 tvb_get_ptr(tvb, offset, sz));
800 sep_offset_prev = sep_offset;
801 sep_offset = tvb_find_guint8(tvb, sep_offset_prev, left,
803 if (sep_offset != -1)
804 sz = sep_offset - offset + 1;
809 proto_tree_add_text(subtree, tvb,
814 tvb_get_ptr(tvb, offset, svsz),
816 tvb_get_ptr(tvb, sep_offset_prev + 1, sz));
821 offset = sep_offset + 1;
828 /*********************************
832 *********************************/
834 icqv5_cmd_ack(proto_tree* tree,/* Tree to put the data in */
835 tvbuff_t *tvb, /* Tvbuff with decrypted packet data */
836 int offset) /* Offset from the start of the packet to the content */
842 ti = proto_tree_add_text(tree,
847 subtree = proto_item_add_subtree(ti, ett_icq_body);
848 proto_tree_add_text(subtree, tvb,
849 offset + CMD_ACK_RANDOM,
852 tvb_get_letohl(tvb, offset + CMD_ACK_RANDOM));
857 icqv5_cmd_rand_search(proto_tree* tree, /* Tree to put the data in */
858 tvbuff_t *tvb, /* Decrypted packet content */
859 int offset, /* Offset from the start of the packet to the content */
860 int size) /* Number of chars left to do */
866 static const char* groups[] = {
882 ti = proto_tree_add_text(tree,
886 "Body (%d bytes, should be 4)", size);
889 ti = proto_tree_add_text(tree,
894 subtree = proto_item_add_subtree(ti, ett_icq_body);
895 group = tvb_get_letohs(tvb, offset + CMD_RAND_SEARCH_GROUP);
896 if (group>0 && (group<=sizeof(groups)/sizeof(const char*)))
897 proto_tree_add_text(subtree, tvb,
898 offset + CMD_RAND_SEARCH_GROUP,
900 "Group: (%u) %s", group, groups[group-1]);
902 proto_tree_add_text(subtree, tvb,
903 offset + CMD_RAND_SEARCH_GROUP,
905 "Group: (%u)", group);
910 icqv5_cmd_ack_messages(proto_tree* tree, /* Tree to put the data in */
911 tvbuff_t *tvb, /* Decrypted packet content */
912 int offset) /* Offset from the start of the packet to the content */
918 ti = proto_tree_add_text(tree,
923 subtree = proto_item_add_subtree(ti, ett_icq_body);
924 proto_tree_add_text(subtree, tvb,
925 offset + CMD_ACK_MESSAGES_RANDOM,
928 tvb_get_letohl(tvb, offset + CMD_ACK_MESSAGES_RANDOM));
933 icqv5_cmd_keep_alive(proto_tree* tree, /* Tree to put the data in */
934 tvbuff_t *tvb, /* Decrypted packet content */
935 int offset) /* Offset from the start of the packet to the content */
942 ti = proto_tree_add_text(tree,
947 subtree = proto_item_add_subtree(ti, ett_icq_body);
948 random = tvb_get_letohl(tvb, offset + CMD_KEEP_ALIVE_RANDOM);
949 proto_tree_add_text(subtree, tvb,
950 offset + CMD_KEEP_ALIVE_RANDOM,
952 "Random: 0x%08x", random);
957 icqv5_cmd_send_text_code(proto_tree* tree, /* Tree to put the data in */
958 tvbuff_t *tvb, /* Decrypted packet content */
959 int offset, /* Offset from the start of the packet to the content */
960 int size) /* Number of chars left to do */
962 proto_tree* subtree = NULL;
963 proto_item* ti = NULL;
968 ti = proto_tree_add_text(tree,
975 len = tvb_get_letohs(tvb, offset+CMD_SEND_TEXT_CODE_LEN);
977 subtree = proto_item_add_subtree(ti, ett_icq_body);
978 proto_tree_add_text(subtree, tvb,
979 offset + CMD_SEND_TEXT_CODE_LEN,
986 proto_tree_add_text(subtree, tvb,
987 offset + CMD_SEND_TEXT_CODE_TEXT,
991 tvb_get_ptr(tvb, offset + CMD_SEND_TEXT_CODE_TEXT,
996 x1 = tvb_get_letohs(tvb, offset + CMD_SEND_TEXT_CODE_TEXT + len);
998 proto_tree_add_text(subtree, tvb,
999 offset + CMD_SEND_TEXT_CODE_TEXT + len,
1006 icqv5_cmd_add_to_list(proto_tree* tree, /* Tree to put the data in */
1007 tvbuff_t *tvb, /* Decrypted packet content */
1008 int offset) /* Offset from the start of the packet to the content */
1011 proto_tree* subtree;
1015 ti = proto_tree_add_text(tree,
1020 subtree = proto_item_add_subtree(ti, ett_icq_body);
1021 uin = tvb_get_letohl(tvb, offset + CMD_ADD_TO_LIST);
1022 proto_tree_add_text(subtree, tvb,
1023 offset + CMD_ADD_TO_LIST_UIN,
1030 icqv5_cmd_status_change(proto_tree* tree, /* Tree to put the data in */
1031 tvbuff_t *tvb, /* Decrypted packet content */
1032 int offset) /* Offset from the start of the packet to the content */
1035 proto_tree* subtree;
1039 ti = proto_tree_add_text(tree,
1044 subtree = proto_item_add_subtree(ti, ett_icq_body);
1045 status = tvb_get_letohl(tvb, offset + CMD_STATUS_CHANGE_STATUS);
1046 proto_tree_add_text(subtree, tvb,
1047 offset + CMD_STATUS_CHANGE_STATUS,
1049 "Status: %s", findStatus(status));
1054 icqv5_cmd_send_msg(proto_tree* tree,
1059 proto_tree* subtree;
1061 int left = size; /* left chars to do */
1065 ti = proto_tree_add_text(tree,
1069 "Body (%d bytes, should be >= 4)", size);
1072 ti = proto_tree_add_text(tree,
1077 subtree = proto_item_add_subtree(ti, ett_icq_body);
1078 proto_tree_add_text(subtree, tvb,
1079 offset + CMD_SEND_MSG_RECV_UIN,
1082 tvb_get_letohl(tvb, offset + CMD_SEND_MSG_RECV_UIN));
1085 icqv5_decode_msgType(subtree,
1087 offset + CMD_SEND_MSG_MSG_TYPE,
1093 icqv5_cmd_login(proto_tree* tree,
1099 proto_tree* subtree;
1104 const guchar *ipAddrp;
1108 ti = proto_tree_add_text(tree,
1113 subtree = proto_item_add_subtree(ti, ett_icq_body);
1114 theTime = tvb_get_letohl(tvb, offset + CMD_LOGIN_TIME);
1115 aTime = ctime(&theTime);
1116 aTime[strlen(aTime)-1] = '\0';
1117 proto_tree_add_text(subtree, tvb,
1118 offset + CMD_LOGIN_TIME,
1120 "Time: %ld = %s", (long)theTime, aTime);
1121 port = tvb_get_letohl(tvb, offset + CMD_LOGIN_PORT);
1122 proto_tree_add_text(subtree, tvb,
1123 offset + CMD_LOGIN_PORT,
1126 passwdLen = tvb_get_letohs(tvb, offset + CMD_LOGIN_PASSLEN);
1127 proto_tree_add_text(subtree, tvb,
1128 offset + CMD_LOGIN_PASSLEN,
1132 tvb_get_ptr(tvb, offset + CMD_LOGIN_PASSWD,
1134 ipAddrp = tvb_get_ptr(tvb,
1135 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP,
1137 proto_tree_add_text(subtree, tvb,
1138 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP,
1140 "IP: %s", ip_to_str(ipAddrp));
1141 status = tvb_get_letohs(tvb,
1142 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS);
1143 proto_tree_add_text(subtree, tvb,
1144 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS,
1146 "Status: %s", findStatus(status));
1151 icqv5_cmd_contact_list(proto_tree* tree,
1156 proto_tree* subtree;
1163 ti = proto_tree_add_text(tree,
1168 subtree = proto_item_add_subtree(ti, ett_icq_body);
1169 num = tvb_get_guint8(tvb, offset + CMD_CONTACT_LIST_NUM);
1170 proto_tree_add_text(subtree, tvb,
1171 offset + CMD_CONTACT_LIST,
1173 "Number of uins: %u", num);
1175 * A sequence of num times UIN follows
1177 offset += (CMD_CONTACT_LIST_NUM + 1);
1178 for (i = 0; i < num; i++) {
1179 uin = tvb_get_letohl(tvb, offset);
1180 proto_tree_add_text(subtree, tvb,
1183 "UIN[%d]: %u", i ,uin);
1190 icqv5_cmd_no_params(proto_tree* tree, /* Tree to put the data in */
1191 tvbuff_t *tvb, /* Decrypted packet content */
1192 int offset) /* Offset from the start of the packet to the content */
1194 proto_tree* subtree;
1198 ti = proto_tree_add_text(tree,
1203 subtree = proto_item_add_subtree(ti, ett_icq_body);
1204 proto_tree_add_text(subtree, tvb,
1211 /**********************
1215 **********************
1218 icqv5_srv_no_params(proto_tree* tree, /* Tree to put the data in */
1219 tvbuff_t *tvb, /* Packet content */
1220 int offset) /* Offset from the start of the packet to the content */
1222 proto_tree* subtree;
1226 ti = proto_tree_add_text(tree,
1231 subtree = proto_item_add_subtree(ti, ett_icq_body);
1232 proto_tree_add_text(subtree, tvb,
1240 icqv5_srv_login_reply(proto_tree* tree,/* Tree to put the data in */
1241 tvbuff_t *tvb, /* Tvbuff with packet */
1242 int offset, /* Offset from the start of the packet to the content */
1243 int size) /* Number of chars left to do */
1245 proto_tree* subtree;
1247 const guchar *ipAddrp;
1250 if (size < SRV_LOGIN_REPLY_IP + 8) {
1251 ti = proto_tree_add_text(tree,
1255 "Body (%d bytes, should be %d)", size,
1256 SRV_LOGIN_REPLY_IP + 8);
1259 ti = proto_tree_add_text(tree,
1262 SRV_LOGIN_REPLY_IP + 8,
1264 subtree = proto_item_add_subtree(ti, ett_icq_body);
1265 ipAddrp = tvb_get_ptr(tvb, offset + SRV_LOGIN_REPLY_IP, 4);
1266 proto_tree_add_text(subtree, tvb,
1267 offset + SRV_LOGIN_REPLY_IP,
1269 "IP: %s", ip_to_str(ipAddrp));
1274 icqv5_srv_user_online(proto_tree* tree,/* Tree to put the data in */
1275 tvbuff_t *tvb, /* Tvbuff with packet */
1276 int offset, /* Offset from the start of the packet to the content */
1277 int size) /* Number of chars left to do */
1279 proto_tree* subtree;
1281 const guchar *ipAddrp;
1282 const guchar *realipAddrp;
1286 if (size < SRV_LOGIN_REPLY_IP + 8) {
1287 ti = proto_tree_add_text(tree,
1291 "Body (%d bytes, should be %d)", size,
1292 SRV_LOGIN_REPLY_IP + 8);
1295 ti = proto_tree_add_text(tree,
1298 SRV_LOGIN_REPLY_IP + 8,
1300 subtree = proto_item_add_subtree(ti, ett_icq_body);
1301 proto_tree_add_text(subtree, tvb,
1302 offset + SRV_USER_ONL_UIN,
1305 tvb_get_letohl(tvb, offset + SRV_USER_ONL_UIN));
1306 ipAddrp = tvb_get_ptr(tvb, offset + SRV_USER_ONL_IP, 4);
1307 proto_tree_add_text(subtree, tvb,
1308 offset + SRV_USER_ONL_IP,
1310 "IP: %s", ip_to_str(ipAddrp));
1311 proto_tree_add_text(subtree, tvb,
1312 offset + SRV_USER_ONL_PORT,
1315 tvb_get_letohl(tvb, offset + SRV_USER_ONL_PORT));
1316 realipAddrp = tvb_get_ptr(tvb, offset + SRV_USER_ONL_REALIP, 4);
1317 proto_tree_add_text(subtree, tvb,
1318 offset + SRV_USER_ONL_REALIP,
1320 "RealIP: %s", ip_to_str(realipAddrp));
1321 status = tvb_get_letohs(tvb, offset + SRV_USER_ONL_STATUS);
1322 proto_tree_add_text(subtree, tvb,
1323 offset + SRV_USER_ONL_STATUS,
1325 "Status: %s", findStatus(status));
1327 * Kojak: Hypothesis is that this field might be an encoding for the
1328 * version used by the UIN that changed. To test this, I included
1329 * this line to the code.
1331 proto_tree_add_text(subtree, tvb,
1332 offset + SRV_USER_ONL_X2,
1335 tvb_get_letohl(tvb, offset + SRV_USER_ONL_X2));
1340 icqv5_srv_user_offline(proto_tree* tree,/* Tree to put the data in */
1341 tvbuff_t *tvb, /* Tvbuff with packet */
1342 int offset, /* Offset from the start of the packet to the content */
1343 int size) /* Number of chars left to do */
1345 proto_tree* subtree;
1349 if (size < SRV_USER_OFFLINE_UIN + 4) {
1350 ti = proto_tree_add_text(tree,
1354 "Body (%d bytes, should be %d)", size,
1355 SRV_USER_OFFLINE_UIN + 4);
1358 ti = proto_tree_add_text(tree,
1361 SRV_USER_OFFLINE_UIN + 4,
1363 subtree = proto_item_add_subtree(ti, ett_icq_body);
1364 proto_tree_add_text(subtree, tvb,
1365 offset + SRV_USER_OFFLINE_UIN,
1368 tvb_get_letohl(tvb, offset + SRV_USER_OFFLINE));
1373 icqv5_srv_multi(proto_tree* tree, /* Tree to put the data in */
1374 tvbuff_t *tvb, /* Packet content */
1375 int offset, /* Offset from the start of the packet to the content */
1376 int size, /* Number of chars left to do */
1379 proto_tree* subtree;
1386 ti = proto_tree_add_text(tree,
1391 subtree = proto_item_add_subtree(ti, ett_icq_body);
1392 num = tvb_get_guint8(tvb, offset + SRV_MULTI_NUM);
1393 proto_tree_add_text(subtree, tvb,
1394 offset + SRV_MULTI_NUM,
1396 "Number of pkts: %u", num);
1398 * A sequence of num times ( pktsize, packetData) follows
1400 offset += (SRV_MULTI_NUM + 1);
1401 for (i = 0; i < num; i++) {
1402 pktSz = tvb_get_letohs(tvb, offset);
1404 dissect_icqv5Server(tvb, offset, pinfo, subtree, pktSz);
1411 icqv5_srv_meta_user(proto_tree* tree, /* Tree to put the data in */
1412 tvbuff_t *tvb, /* Tvbuff with packet */
1413 int offset, /* Offset from the start of the packet to the content */
1414 int size) /* Number of chars left to do */
1417 proto_tree* subtree = NULL;
1419 proto_tree* sstree = NULL;
1420 proto_item* ti = NULL;
1423 unsigned char result;
1427 ti = proto_tree_add_text(tree,
1432 subtree = proto_item_add_subtree(ti, ett_icq_body);
1433 subcmd = tvb_get_letohs(tvb, offset + SRV_META_USER_SUBCMD);
1434 ti = proto_tree_add_text(subtree, tvb,
1435 offset + SRV_META_USER_SUBCMD,
1437 "%s", findSubCmd(subcmd));
1438 result = tvb_get_guint8(tvb, offset + SRV_META_USER_RESULT);
1439 proto_tree_add_text(subtree, tvb,
1440 offset + SRV_META_USER_RESULT,
1442 "%s", (result==0x0a)?"Success":"Failure");
1443 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1445 subcmd = tvb_get_letohs(tvb, offset + SRV_META_USER_SUBCMD);
1446 ti = proto_tree_add_text(tree, tvb,
1447 offset + SRV_META_USER_SUBCMD,
1449 "%s", findSubCmd(subcmd));
1450 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1451 result = tvb_get_guint8(tvb, offset + SRV_META_USER_RESULT);
1452 proto_tree_add_text(sstree, tvb,
1453 offset + SRV_META_USER_RESULT,
1455 "%s", (result==0x0a)?"Success":"Failure");
1458 /* Skip the META_USER header */
1463 case META_EX_USER_FOUND:
1465 /* This is almost the same as META_USER_FOUND,
1466 * however, there's an extra length field
1470 /* Read the length field */
1471 pktLen = tvb_get_letohs(tvb, offset);
1472 proto_tree_add_text(sstree, tvb,
1475 "Length: %u", pktLen);
1477 offset += sizeof(guint16); left -= sizeof(guint16);
1479 case META_USER_FOUND:
1481 /* The goto mentioned in this block should be local to this
1482 * block if C'd allow it.
1484 * They are used to "implement" a poorman's exception handling
1498 proto_tree_add_text(sstree, tvb,
1502 tvb_get_letohl(tvb, offset));
1503 offset+=sizeof(guint32);left-=sizeof(guint32);
1505 for ( ; *d!=NULL; d++) {
1506 len = proto_add_icq_attr(sstree,
1512 offset += len; left -= len;
1514 /* Get the authorize setting */
1515 auth = tvb_get_guint8(tvb, offset);
1516 proto_tree_add_text(sstree, tvb,
1519 "authorization: %s", (auth==0x01)?"Neccessary":"Who needs it");
1522 proto_tree_add_text(sstree, tvb,
1526 tvb_get_letohs(tvb, offset));
1527 offset+=sizeof(guint16);left-=sizeof(guint16);
1529 proto_tree_add_text(sstree, tvb,
1533 tvb_get_letohl(tvb, offset));
1534 offset+=sizeof(guint32);left-=sizeof(guint32);
1541 /* Get the about information */
1542 len = tvb_get_letohs(tvb, offset);
1543 offset+=sizeof(guint16);left-=sizeof(guint16);
1544 proto_tree_add_text(sstree, tvb,
1545 offset - sizeof(guint16),
1546 sizeof(guint16)+len,
1547 "About(%d): %.*s", len,
1548 len, tvb_get_ptr(tvb, offset, len));
1549 offset+=len;left-=len;
1552 case META_USER_INFO:
1554 /* The goto mentioned in this block should be local to this
1555 * block if C'd allow it.
1557 * They are used to "implement" a poorman's exception handling
1559 static const char* descr[] = {
1574 const char** d = descr;
1576 guint8 user_timezone;
1581 uin = tvb_get_letohl(tvb, offset);
1582 proto_tree_add_text(sstree, tvb,
1586 offset+=sizeof(guint32);left-=sizeof(guint32);
1590 * Get every field from the description
1592 while ((*d)!=NULL) {
1593 len = tvb_get_letohs(tvb, offset);
1594 offset+=sizeof(guint16);left-=sizeof(guint16);
1596 proto_tree_add_text(sstree, tvb,
1597 offset - sizeof(guint16),
1598 sizeof(guint16)+len,
1599 "%s(%d): %.*s",*d, len,
1601 tvb_get_ptr(tvb, offset, len - 1));
1602 offset+=len;left-=len;
1606 /* Get country code */
1607 country = tvb_get_letohs(tvb, offset);
1608 proto_tree_add_text(sstree, tvb,
1611 "Countrycode: %u", country);
1612 offset+=sizeof(guint16); left-=sizeof(guint16);
1613 /* Get the timezone setting */
1614 user_timezone = tvb_get_guint8(tvb, offset);
1615 proto_tree_add_text(sstree, tvb,
1617 sizeof(unsigned char),
1618 "Timezone: %u", user_timezone);
1620 /* Get the authorize setting */
1621 auth = tvb_get_guint8(tvb, offset);
1622 proto_tree_add_text(sstree, tvb,
1624 sizeof(unsigned char),
1625 "Authorization: (%u) %s",
1626 auth, (auth==0)?"No":"Yes");
1628 /* Get the webaware setting */
1629 auth = tvb_get_guint8(tvb, offset);
1630 proto_tree_add_text(sstree, tvb,
1632 sizeof(unsigned char),
1633 "Webaware: (%u) %s",
1634 auth, (auth==0)?"No":"Yes");
1636 /* Get the authorize setting */
1637 auth = tvb_get_guint8(tvb, offset);
1638 proto_tree_add_text(sstree, tvb,
1640 sizeof(unsigned char),
1642 auth, (auth==0)?"No":"Yes");
1647 /* This information is already printed in the tree */
1648 fprintf(stderr, "Meta subcmd: %04x\n", subcmd);
1655 icqv5_srv_recv_message(proto_tree* tree, /* Tree to put the data in */
1656 tvbuff_t* tvb, /* Packet content */
1657 int offset, /* Offset from the start of the packet to the content */
1658 int size) /* Number of chars left to do */
1660 proto_tree* subtree = NULL;
1661 proto_item* ti = NULL;
1670 ti = proto_tree_add_text(tree,
1675 subtree = proto_item_add_subtree(ti, ett_icq_body);
1676 proto_tree_add_item(subtree,
1679 offset + SRV_RECV_MSG_UIN,
1682 year = tvb_get_letohs(tvb, offset + SRV_RECV_MSG_YEAR);
1683 month = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_MONTH);
1684 day = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_DAY);
1685 hour = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_HOUR);
1686 minute = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_MINUTE);
1688 proto_tree_add_text(subtree, tvb,
1689 offset + SRV_RECV_MSG_YEAR,
1690 sizeof(guint16) + 4*sizeof(unsigned char),
1691 "Time: %u-%u-%u %02u:%02u",
1692 day, month, year, hour, minute);
1693 icqv5_decode_msgType(subtree,
1695 offset + SRV_RECV_MSG_MSG_TYPE,
1701 icqv5_srv_rand_user(proto_tree* tree, /* Tree to put the data in */
1702 tvbuff_t *tvb, /* Tvbuff with packet */
1703 int offset) /* Offset from the start of the packet to the content */
1705 proto_tree* subtree = NULL;
1706 proto_item* ti = NULL;
1708 const unsigned char* IP = NULL;
1710 const unsigned char* realIP = NULL;
1716 ti = proto_tree_add_text(tree,
1719 SRV_RAND_USER_TCP_VER + 2,
1721 subtree = proto_item_add_subtree(ti, ett_icq_body);
1723 uin = tvb_get_letohl(tvb, offset + SRV_RAND_USER_UIN);
1724 proto_tree_add_text(subtree, tvb,
1725 offset + SRV_RAND_USER_UIN,
1729 IP = tvb_get_ptr(tvb, offset + SRV_RAND_USER_IP, 4);
1730 proto_tree_add_text(subtree, tvb,
1731 offset + SRV_RAND_USER_IP,
1735 /* guint16 portNum */
1736 /* XXX - 16 bits, or 32 bits? */
1737 port = tvb_get_letohs(tvb, offset + SRV_RAND_USER_PORT);
1738 proto_tree_add_text(subtree, tvb,
1739 offset + SRV_RAND_USER_UIN,
1742 /* guint32 realIP */
1743 realIP = tvb_get_ptr(tvb, offset + SRV_RAND_USER_REAL_IP, 4);
1744 proto_tree_add_text(subtree, tvb,
1745 offset + SRV_RAND_USER_REAL_IP,
1747 "RealIP: %s", ip_to_str(realIP));
1748 /* guint8 Communication Class */
1749 commClass = tvb_get_guint8(tvb, offset + SRV_RAND_USER_CLASS);
1750 proto_tree_add_text(subtree, tvb,
1751 offset + SRV_RAND_USER_CLASS,
1753 "Class: %s", (commClass!=4)?"User to User":"Through Server");
1754 /* guint32 status */
1755 /* XXX - 16 bits, or 32 bits? */
1756 status = tvb_get_letohs(tvb, offset + SRV_RAND_USER_STATUS);
1757 proto_tree_add_text(subtree, tvb,
1758 offset + SRV_RAND_USER_STATUS,
1760 "Status: %s", findStatus(status));
1761 /* guint16 tcpVersion */
1762 tcpVer = tvb_get_letohs(tvb, offset + SRV_RAND_USER_TCP_VER);
1763 proto_tree_add_text(subtree, tvb,
1764 offset + SRV_RAND_USER_TCP_VER,
1766 "TCPVersion: %u", tcpVer);
1771 * Dissect all the v5 client traffic. This is encrypted, so be careful.
1774 dissect_icqv5Client(tvbuff_t *tvb,
1778 proto_tree *icq_tree = NULL;
1779 proto_tree *icq_header_tree = NULL;
1780 proto_item *ti = NULL;
1782 int pktsize; /* The actual size of the ICQ content */
1783 int capturedsize; /* The captured size of the ICQ content */
1784 guint32 rounded_size;
1787 guint8 *decr_pd; /* Decrypted content */
1790 pktsize = tvb_reported_length(tvb);
1791 capturedsize = tvb_length(tvb);
1793 /* Get the encryption key */
1794 key = get_v5key(tvb, pktsize);
1797 * Make a copy of the packet data, and decrypt it.
1798 * The decryption processes 4 bytes at a time, and starts at
1799 * an offset of ICQ5_CL_SESSIONID (which isn't a multiple of 4),
1800 * so we make sure that there are
1802 * (ICQ5_CL_SESSIONID + a multiple of 4)
1804 * bytes in the buffer.
1806 rounded_size = ((((capturedsize - ICQ5_CL_SESSIONID) + 3)/4)*4) + ICQ5_CL_SESSIONID;
1807 decr_pd = g_malloc(rounded_size);
1808 tvb_memcpy(tvb, decr_pd, 0, capturedsize);
1809 decrypt_v5(decr_pd, rounded_size, key);
1811 /* Allocate a new tvbuff, referring to the decrypted data. */
1812 decr_tvb = tvb_new_real_data(decr_pd, capturedsize, pktsize);
1814 /* Arrange that the allocated packet data copy be freed when the
1816 tvb_set_free_cb(decr_tvb, g_free);
1818 /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
1819 were handed refers, so it'll get cleaned up when that tvbuff
1821 tvb_set_child_real_data_tvbuff(tvb, decr_tvb);
1823 /* Add the decrypted data to the data source list. */
1824 add_new_data_source(pinfo, decr_tvb, "Decrypted");
1826 cmd = tvb_get_letohs(decr_tvb, ICQ5_CL_CMD);
1828 if (check_col(pinfo->cinfo, COL_INFO))
1829 col_add_fstr(pinfo->cinfo, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
1832 ti = proto_tree_add_protocol_format(tree,
1837 "ICQv5 %s (len %u)",
1840 icq_tree = proto_item_add_subtree(ti, ett_icq);
1841 ti = proto_tree_add_uint_format(icq_tree,
1848 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
1850 proto_tree_add_text(icq_header_tree, tvb,
1854 tvb_get_letohs(tvb, ICQ_VERSION));
1855 proto_tree_add_item(icq_header_tree,
1861 proto_tree_add_item(icq_header_tree,
1867 proto_tree_add_uint_format(icq_header_tree,
1874 val_to_str(cmd, clientCmdCode, "Unknown"), cmd);
1875 proto_tree_add_text(icq_header_tree, decr_tvb,
1878 "Seq Number 1: 0x%04x",
1879 tvb_get_letohs(decr_tvb, ICQ5_CL_SEQNUM1));
1880 proto_tree_add_text(icq_header_tree, decr_tvb,
1883 "Seq Number 2: 0x%04x",
1884 tvb_get_letohs(decr_tvb, ICQ5_CL_SEQNUM2));
1885 proto_tree_add_uint_format(icq_header_tree,
1895 icqv5_cmd_ack(icq_tree,
1900 case CMD_MSG_TO_NEW_USER:
1901 icqv5_cmd_send_msg(icq_tree,
1904 pktsize - ICQ5_CL_HDRSIZE);
1906 case CMD_RAND_SEARCH:
1907 icqv5_cmd_rand_search(icq_tree,
1910 pktsize - ICQ5_CL_HDRSIZE);
1913 icqv5_cmd_login(icq_tree,
1916 pktsize - ICQ5_CL_HDRSIZE);
1918 case CMD_SEND_TEXT_CODE:
1919 icqv5_cmd_send_text_code(icq_tree,
1922 pktsize - ICQ5_CL_HDRSIZE);
1924 case CMD_STATUS_CHANGE:
1925 icqv5_cmd_status_change(icq_tree,
1929 case CMD_ACK_MESSAGES:
1930 icqv5_cmd_ack_messages(icq_tree,
1934 case CMD_KEEP_ALIVE:
1935 icqv5_cmd_keep_alive(icq_tree,
1939 case CMD_ADD_TO_LIST:
1940 icqv5_cmd_add_to_list(icq_tree,
1944 case CMD_CONTACT_LIST:
1945 icqv5_cmd_contact_list(icq_tree,
1948 pktsize - ICQ5_CL_HDRSIZE);
1951 case CMD_REG_NEW_USER:
1952 case CMD_QUERY_SERVERS:
1953 case CMD_QUERY_ADDONS:
1954 icqv5_cmd_no_params(icq_tree,
1959 proto_tree_add_text(icq_tree,
1962 pktsize - ICQ5_CL_HDRSIZE,
1964 fprintf(stderr,"Missing: %s\n", findClientCmd(cmd));
1971 dissect_icqv5Server(tvbuff_t *tvb,
1977 /* Server traffic is easy, not encrypted */
1978 proto_tree *icq_tree = NULL;
1979 proto_tree *icq_header_tree = NULL;
1980 proto_item *ti = NULL;
1981 int changeCol = (pktsize==-1);
1985 cmd = tvb_get_letohs(tvb, offset + ICQ5_SRV_CMD);
1986 if (changeCol && check_col(pinfo->cinfo, COL_INFO))
1987 col_add_fstr(pinfo->cinfo, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
1990 pktsize = tvb_reported_length(tvb);
1993 ti = proto_tree_add_protocol_format(tree,
1998 "ICQv5 %s (len %u)",
2002 icq_tree = proto_item_add_subtree(ti, ett_icq);
2004 ti = proto_tree_add_uint_format(icq_tree,
2011 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
2013 proto_tree_add_text(icq_header_tree, tvb,
2014 offset + ICQ_VERSION,
2017 tvb_get_letohs(tvb, ICQ_VERSION));
2018 proto_tree_add_item(icq_header_tree,
2021 offset + ICQ5_SRV_SESSIONID,
2024 proto_tree_add_uint_format(icq_header_tree,
2027 offset + ICQ5_SRV_CMD,
2031 val_to_str(cmd, serverCmdCode, "Unknown"), cmd);
2032 proto_tree_add_text(icq_header_tree, tvb,
2033 offset + ICQ5_SRV_SEQNUM1,
2035 "Seq Number 1: 0x%04x",
2036 tvb_get_letohs(tvb, offset + ICQ5_SRV_SEQNUM1));
2037 proto_tree_add_text(icq_header_tree, tvb,
2038 offset + ICQ5_SRV_SEQNUM2,
2040 "Seq Number 2: 0x%04x",
2041 tvb_get_letohs(tvb, offset + ICQ5_SRV_SEQNUM2));
2042 proto_tree_add_item(icq_header_tree,
2045 offset + ICQ5_SRV_UIN,
2048 proto_tree_add_item(icq_header_tree,
2051 offset + ICQ5_SRV_CHECKCODE,
2056 icqv5_srv_rand_user(icq_tree,
2058 offset + ICQ5_SRV_HDRSIZE);
2060 case SRV_SYS_DELIVERED_MESS:
2061 /* The message structures are all the same. Why not run
2062 * the same routine? */
2063 icqv5_cmd_send_msg(icq_tree,
2065 offset + ICQ5_SRV_HDRSIZE,
2066 pktsize - ICQ5_SRV_HDRSIZE);
2068 case SRV_USER_ONLINE:
2069 icqv5_srv_user_online(icq_tree,
2071 offset + ICQ5_SRV_HDRSIZE,
2072 pktsize - ICQ5_SRV_HDRSIZE);
2074 case SRV_USER_OFFLINE:
2075 icqv5_srv_user_offline(icq_tree,
2077 offset + ICQ5_SRV_HDRSIZE,
2078 pktsize - ICQ5_SRV_HDRSIZE);
2080 case SRV_LOGIN_REPLY:
2081 icqv5_srv_login_reply(icq_tree,
2083 offset + ICQ5_SRV_HDRSIZE,
2084 pktsize - ICQ5_SRV_HDRSIZE);
2087 icqv5_srv_meta_user(icq_tree,
2089 offset + ICQ5_SRV_HDRSIZE,
2090 pktsize - ICQ5_SRV_HDRSIZE);
2092 case SRV_RECV_MESSAGE:
2093 icqv5_srv_recv_message(icq_tree,
2095 offset + ICQ5_SRV_HDRSIZE,
2096 pktsize - ICQ5_SRV_HDRSIZE);
2099 icqv5_srv_multi(icq_tree,
2101 offset + ICQ5_SRV_HDRSIZE,
2102 pktsize - ICQ5_SRV_HDRSIZE,
2106 case SRV_SILENT_TOO_LONG:
2110 case SRV_UPDATE_SUCCESS:
2111 icqv5_srv_no_params(icq_tree,
2113 offset + ICQ5_SRV_HDRSIZE);
2116 proto_tree_add_text(icq_tree,
2118 offset + ICQ5_SRV_HDRSIZE,
2119 pktsize - ICQ5_SRV_HDRSIZE,
2121 fprintf(stderr,"Missing: %s\n", findServerCmd(cmd));
2127 static void dissect_icqv5(tvbuff_t *tvb,
2133 if (check_col(pinfo->cinfo, COL_PROTOCOL))
2134 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQv5 (UDP)");
2135 if (check_col(pinfo->cinfo, COL_INFO))
2136 col_set_str(pinfo->cinfo, COL_INFO, "ICQv5 packet");
2138 unknown = tvb_get_letohl(tvb, ICQ5_UNKNOWN);
2140 if (unknown == 0x0L) {
2141 dissect_icqv5Client(tvb, pinfo, tree);
2143 dissect_icqv5Server(tvb, 0, pinfo, tree, -1);
2147 static void dissect_icq(tvbuff_t *tvb,
2153 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
2154 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQ");
2156 if (check_col(pinfo->cinfo, COL_INFO)) {
2157 col_clear(pinfo->cinfo, COL_INFO);
2160 version = tvb_get_letohs(tvb, ICQ_VERSION);
2163 dissect_icqv5(tvb, pinfo, tree);
2166 dissect_icqv4(tvb, pinfo, tree);
2169 dissect_icqv3(tvb, pinfo, tree);
2172 dissect_icqv2(tvb, pinfo, tree);
2175 fprintf(stderr, "ICQ: Unknown version (%d)\n", version);
2180 /* registration with the filtering engine */
2182 proto_register_icq(void)
2184 static hf_register_info hf[] = {
2186 {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2188 {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2189 { &hf_icq_sessionid,
2190 {"Session ID", "icq.sessionid", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2191 { &hf_icq_client_cmd,
2192 {"Client command", "icq.client_cmd", FT_UINT16, BASE_HEX, VALS(clientCmdCode), 0x0, "", HFILL }},
2193 { &hf_icq_server_cmd,
2194 {"Server command", "icq.server_cmd", FT_UINT16, BASE_DEC, VALS(serverCmdCode), 0x0, "", HFILL }},
2195 { &hf_icq_checkcode,
2196 {"Checkcode", "icq.checkcode", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2198 {"Decode", "icq.decode", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}
2200 static gint *ett[] = {
2205 &ett_icq_body_parts,
2208 proto_icq = proto_register_protocol("ICQ Protocol", "ICQ", "icq");
2210 proto_register_field_array(proto_icq, hf, array_length(hf));
2212 proto_register_subtree_array(ett, array_length(ett));
2216 proto_reg_handoff_icq(void)
2218 dissector_handle_t icq_handle;
2220 icq_handle = create_dissector_handle(dissect_icq, proto_icq);
2221 dissector_add("udp.port", UDP_PORT_ICQ, icq_handle);