2 * Routines for ICQ packet disassembly
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
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/addr_resolv.h>
50 #include <epan/expert.h>
52 static int proto_icq = -1;
53 static int hf_icq_uin = -1;
54 static int hf_icq_client_cmd = -1;
55 static int hf_icq_server_cmd = -1;
56 static int hf_icq_sessionid = -1;
57 static int hf_icq_checkcode = -1;
58 static int hf_icq_decode = -1;
59 static int hf_icq_type = -1;
61 static gint ett_icq = -1;
62 static gint ett_icq_header = -1;
63 static gint ett_icq_decode = -1;
64 static gint ett_icq_body = -1;
65 static gint ett_icq_body_parts = -1;
67 /* This is not IANA registered */
68 #define UDP_PORT_ICQ 4000
70 enum { ICQ5_client, ICQ5_server};
72 static void dissect_icqv5(tvbuff_t *tvb,
77 dissect_icqv5Server(tvbuff_t *tvb,
83 /* Offsets of fields in the ICQ headers */
84 /* Can be 0x0002 or 0x0005 */
85 #define ICQ_VERSION 0x00
86 /* Is either one (server) or four (client) bytes long */
87 /* Client header offsets */
88 #define ICQ5_UNKNOWN 0x02
89 #define ICQ5_CL_UIN 0x06
90 #define ICQ5_CL_SESSIONID 0x0a
91 #define ICQ5_CL_CMD 0x0e
92 #define ICQ5_CL_SEQNUM1 0x10
93 #define ICQ5_CL_SEQNUM2 0x12
94 #define ICQ5_CL_CHECKCODE 0x14
95 #define ICQ5_CL_PARAM 0x18
96 #define ICQ5_CL_HDRSIZE 0x18
98 /* Server header offsets */
99 #define ICQ5_SRV_SESSIONID 0x03
100 #define ICQ5_SRV_CMD 0x07
101 #define ICQ5_SRV_SEQNUM1 0x09
102 #define ICQ5_SRV_SEQNUM2 0x0b
103 #define ICQ5_SRV_UIN 0x0d
104 #define ICQ5_SRV_CHECKCODE 0x11
105 #define ICQ5_SRV_PARAM 0x15
106 #define ICQ5_SRV_HDRSIZE 0x15
108 #define SRV_ACK 0x000a
110 #define SRV_SILENT_TOO_LONG 0x001e
112 #define SRV_GO_AWAY 0x0028
114 #define SRV_NEW_UIN 0x0046
116 /* LOGIN_REPLY is very scary. It has a lot of fields that are undocumented
117 * Only the IP field makes sense */
118 #define SRV_LOGIN_REPLY 0x005a
119 #define SRV_LOGIN_REPLY_IP 0x000c
121 #define SRV_BAD_PASS 0x0064
123 #define SRV_USER_ONLINE 0x006e
124 #define SRV_USER_ONL_UIN 0x0000
125 #define SRV_USER_ONL_IP 0x0004
126 #define SRV_USER_ONL_PORT 0x0008
127 #define SRV_USER_ONL_REALIP 0x000c
128 #define SRV_USER_ONL_X1 0x0010
129 #define SRV_USER_ONL_STATUS 0x0013
130 #define SRV_USER_ONL_X2 0x0015
132 #define SRV_USER_OFFLINE 0x0078
133 #define SRV_USER_OFFLINE_UIN 0x0000
135 #define SRV_MULTI 0x0212
136 #define SRV_MULTI_NUM 0x0000
138 #define SRV_META_USER 0x03de
139 #define SRV_META_USER_SUBCMD 0x0000
140 #define SRV_META_USER_RESULT 0x0002
141 #define SRV_META_USER_DATA 0x0003
143 #define SRV_UPDATE_SUCCESS 0x01e0
145 #define SRV_UPDATE_FAIL 0x01ea
148 * ICQv5 SRV_META_USER subcommands
150 #define META_EX_USER_FOUND 0x0190
151 #define META_USER_FOUND 0x019a
152 #define META_ABOUT 0x00e6
153 #define META_USER_INFO 0x00c8
155 #define SRV_RECV_MESSAGE 0x00dc
156 #define SRV_RECV_MSG_UIN 0x0000
157 #define SRV_RECV_MSG_YEAR 0x0004
158 #define SRV_RECV_MSG_MONTH 0x0006
159 #define SRV_RECV_MSG_DAY 0x0007
160 #define SRV_RECV_MSG_HOUR 0x0008
161 #define SRV_RECV_MSG_MINUTE 0x0009
162 #define SRV_RECV_MSG_MSG_TYPE 0x000a
164 #define SRV_RAND_USER 0x024e
165 #define SRV_RAND_USER_UIN 0x0000
166 #define SRV_RAND_USER_IP 0x0004
167 #define SRV_RAND_USER_PORT 0x0008
168 #define SRV_RAND_USER_REAL_IP 0x000c
169 #define SRV_RAND_USER_CLASS 0x0010
170 #define SRV_RAND_USER_X1 0x0011
171 #define SRV_RAND_USER_STATUS 0x0015
172 #define SRV_RAND_USER_TCP_VER 0x0019
174 /* This message has the same structure as cmd_send_msg */
175 #define SRV_SYS_DELIVERED_MESS 0x0104
177 static const value_string serverMetaSubCmdCode[] = {
178 { META_USER_FOUND, "META_USER_FOUND" },
179 { META_EX_USER_FOUND, "META_EX_USER_FOUND" },
180 { META_ABOUT, "META_ABOUT" },
181 { META_USER_INFO, "META_USER_INFO" },
185 static const value_string serverCmdCode[] = {
186 { SRV_ACK, "SRV_ACK" },
187 { SRV_SILENT_TOO_LONG, "SRV_SILENT_TOO_LONG" },
188 { SRV_GO_AWAY, "SRV_GO_AWAY" },
189 { SRV_NEW_UIN, "SRV_NEW_UIN" },
190 { SRV_LOGIN_REPLY, "SRV_LOGIN_REPLY" },
191 { SRV_BAD_PASS, "SRV_BAD_PASS" },
192 { SRV_USER_ONLINE, "SRV_USER_ONLINE" },
193 { SRV_USER_OFFLINE, "SRV_USER_OFFLINE" },
194 { 130, "SRV_QUERY" },
195 { 140, "SRV_USER_FOUND" },
196 { 160, "SRV_END_OF_SEARCH" },
197 { 180, "SRV_NEW_USER" },
198 { 200, "SRV_UPDATE_EXT" },
199 { SRV_RECV_MESSAGE, "SRV_RECV_MESSAGE" },
200 { 230, "SRV_END_OFFLINE_MESSAGES" },
201 { 240, "SRV_NOT_CONNECTED" },
202 { 250, "SRV_TRY_AGAIN" },
203 { SRV_SYS_DELIVERED_MESS, "SRV_SYS_DELIVERED_MESS" },
204 { 280, "SRV_INFO_REPLY" },
205 { 290, "SRV_EXT_INFO_REPLY" },
206 { 420, "SRV_STATUS_UPDATE" },
207 { 450, "SRV_SYSTEM_MESSAGE" },
208 { SRV_UPDATE_SUCCESS, "SRV_UPDATE_SUCCESS" },
209 { SRV_UPDATE_FAIL, "SRV_UPDATE_FAIL" },
210 { 500, "SRV_AUTH_UPDATE" },
211 { SRV_MULTI, "SRV_MULTI_PACKET" },
212 { 540, "SRV_END_CONTACTLIST_STATUS" },
213 { SRV_RAND_USER, "SRV_RAND_USER" },
214 { SRV_META_USER, "SRV_META_USER" },
218 #define MSG_TEXT 0x0001
219 #define MSG_URL 0x0004
220 #define MSG_AUTH_REQ 0x0006
221 #define MSG_AUTH 0x0008
222 #define MSG_USER_ADDED 0x000c
223 #define MSG_EMAIL 0x000e
224 #define MSG_CONTACTS 0x0013
226 #define STATUS_ONLINE 0x00000000
227 #define STATUS_AWAY 0x00000001
228 #define STATUS_DND 0x00000013
229 #define STATUS_INVISIBLE 0x00000100
230 #define STATUS_OCCUPIED 0x00000010
231 #define STATUS_NA 0x00000004
232 #define STATUS_CHAT 0x00000020
234 /* Offsets for all packets measured from the start of the payload; i.e.
235 * with the ICQ header removed
237 #define CMD_ACK 0x000a
238 #define CMD_ACK_RANDOM 0x0000
240 #define CMD_SEND_MSG 0x010E
241 #define CMD_SEND_MSG_RECV_UIN 0x0000
242 #define CMD_SEND_MSG_MSG_TYPE 0x0004
243 #define CMD_SEND_MSG_MSG_LEN 0x0006
244 #define CMD_SEND_MSG_MSG_TEXT 0x0008
245 /* The rest of the packet should be a null-term string */
247 #define CMD_LOGIN 0x03E8
248 #define CMD_LOGIN_TIME 0x0000
249 #define CMD_LOGIN_PORT 0x0004
250 #define CMD_LOGIN_PASSLEN 0x0008
251 #define CMD_LOGIN_PASSWD 0x000A
252 /* The password is variable length; so when we've decoded the passwd,
253 * the structure starts counting at 0 again.
255 #define CMD_LOGIN_IP 0x0004
256 #define CMD_LOGIN_STATUS 0x0009
258 #define CMD_CONTACT_LIST 0x0406
259 #define CMD_CONTACT_LIST_NUM 0x0000
261 #define CMD_USER_META 0x064a
263 #define CMD_REG_NEW_USER 0x03fc
265 #define CMD_ACK_MESSAGES 0x0442
266 #define CMD_ACK_MESSAGES_RANDOM 0x0000
268 #define CMD_KEEP_ALIVE 0x042e
269 #define CMD_KEEP_ALIVE_RANDOM 0x0000
271 #define CMD_SEND_TEXT_CODE 0x0438
272 #define CMD_SEND_TEXT_CODE_LEN 0x0000
273 #define CMD_SEND_TEXT_CODE_TEXT 0x0002
275 #define CMD_MSG_TO_NEW_USER 0x0456
277 #define CMD_QUERY_SERVERS 0x04ba
279 #define CMD_QUERY_ADDONS 0x04c4
281 #define CMD_STATUS_CHANGE 0x04d8
282 #define CMD_STATUS_CHANGE_STATUS 0x0000
284 #define CMD_ADD_TO_LIST 0x053c
285 #define CMD_ADD_TO_LIST_UIN 0x0000
287 #define CMD_RAND_SEARCH 0x056e
288 #define CMD_RAND_SEARCH_GROUP 0x0000
290 #define CMD_META_USER 0x064a
292 static const value_string msgTypeCode[] = {
293 { MSG_TEXT, "MSG_TEXT" },
294 { MSG_URL, "MSG_URL" },
295 { MSG_AUTH_REQ, "MSG_AUTH_REQ" },
296 { MSG_AUTH, "MSG_AUTH" },
297 { MSG_USER_ADDED, "MSG_USER_ADDED" },
298 { MSG_EMAIL, "MSG_EMAIL" },
299 { MSG_CONTACTS, "MSG_CONTACTS" },
303 static const value_string statusCode[] = {
304 { STATUS_ONLINE, "ONLINE" },
305 { STATUS_AWAY, "AWAY" },
306 { STATUS_DND, "DND" },
307 { STATUS_INVISIBLE, "INVISIBLE" },
308 { STATUS_OCCUPIED, "OCCUPIED" },
310 { STATUS_CHAT, "Free for Chat" },
314 static const value_string clientCmdCode[] = {
315 { CMD_ACK, "CMD_ACK" },
316 { CMD_SEND_MSG, "CMD_SEND_MESSAGE" },
317 { CMD_LOGIN, "CMD_LOGIN" },
318 { CMD_REG_NEW_USER, "CMD_REG_NEW_USER" },
319 { 1030, "CMD_CONTACT_LIST" },
320 { 1050, "CMD_SEARCH_UIN" },
321 { 1060, "CMD_SEARCH_USER" },
322 { 1070, "CMD_KEEP_ALIVE" },
323 { CMD_SEND_TEXT_CODE, "CMD_SEND_TEXT_CODE" },
324 { CMD_ACK_MESSAGES, "CMD_ACK_MESSAGES" },
325 { 1100, "CMD_LOGIN_1" },
326 { CMD_MSG_TO_NEW_USER, "CMD_MSG_TO_NEW_USER" },
327 { 1120, "CMD_INFO_REQ" },
328 { 1130, "CMD_EXT_INFO_REQ" },
329 { 1180, "CMD_CHANGE_PW" },
330 { 1190, "CMD_NEW_USER_INFO" },
331 { 1200, "CMD_UPDATE_EXT_INFO" },
332 { CMD_QUERY_SERVERS, "CMD_QUERY_SERVERS" },
333 { CMD_QUERY_ADDONS, "CMD_QUERY_ADDONS" },
334 { CMD_STATUS_CHANGE, "CMD_STATUS_CHANGE" },
335 { 1260, "CMD_NEW_USER_1" },
336 { 1290, "CMD_UPDATE_INFO" },
337 { 1300, "CMD_AUTH_UPDATE" },
338 { 1310, "CMD_KEEP_ALIVE2" },
339 { 1320, "CMD_LOGIN_2" },
340 { CMD_ADD_TO_LIST, "CMD_ADD_TO_LIST" },
341 { 1380, "CMD_RAND_SET" },
342 { CMD_RAND_SEARCH, "CMD_RAND_SEARCH" },
343 { CMD_META_USER, "CMD_META_USER" },
344 { 1700, "CMD_INVIS_LIST" },
345 { 1710, "CMD_VIS_LIST" },
346 { 1720, "CMD_UPDATE_LIST" },
351 * All ICQv5 decryption code thanx to Sebastien Dault (daus01@gel.usherb.ca)
355 0x59, 0x60, 0x37, 0x6B, 0x65, 0x62, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x60, 0x57, 0x5B, 0x3D,
356 0x5E, 0x34, 0x6D, 0x36, 0x50, 0x3F, 0x6F, 0x67, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x47, 0x63, 0x39,
357 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x43, 0x69, 0x48, 0x33, 0x31, 0x64, 0x35, 0x5A, 0x4A, 0x42,
358 0x56, 0x40, 0x67, 0x53, 0x41, 0x07, 0x6C, 0x49, 0x58, 0x3B, 0x4D, 0x46, 0x68, 0x43, 0x69, 0x48,
359 0x33, 0x31, 0x44, 0x65, 0x62, 0x46, 0x48, 0x53, 0x41, 0x07, 0x6C, 0x69, 0x48, 0x33, 0x51, 0x54,
360 0x5D, 0x4E, 0x6C, 0x49, 0x38, 0x4B, 0x55, 0x4A, 0x62, 0x46, 0x48, 0x33, 0x51, 0x34, 0x6D, 0x36,
361 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x63, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64, 0x35, 0x5A,
362 0x6A, 0x52, 0x6E, 0x3C, 0x51, 0x34, 0x6D, 0x36, 0x50, 0x5F, 0x5F, 0x3F, 0x4F, 0x37, 0x4B, 0x35,
363 0x5A, 0x4A, 0x62, 0x66, 0x58, 0x3B, 0x4D, 0x66, 0x58, 0x5B, 0x5D, 0x4E, 0x6C, 0x49, 0x58, 0x3B,
364 0x4D, 0x66, 0x58, 0x3B, 0x4D, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64,
365 0x55, 0x6A, 0x32, 0x3E, 0x44, 0x45, 0x52, 0x6E, 0x3C, 0x31, 0x64, 0x55, 0x6A, 0x52, 0x4E, 0x6C,
366 0x69, 0x48, 0x53, 0x61, 0x4C, 0x39, 0x30, 0x6F, 0x47, 0x63, 0x59, 0x60, 0x57, 0x5B, 0x3D, 0x3E,
367 0x64, 0x35, 0x3A, 0x3A, 0x5A, 0x6A, 0x52, 0x4E, 0x6C, 0x69, 0x48, 0x53, 0x61, 0x6C, 0x49, 0x58,
368 0x3B, 0x4D, 0x46, 0x68, 0x63, 0x39, 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x67, 0x53, 0x41, 0x25, 0x41,
369 0x3C, 0x51, 0x54, 0x3D, 0x5E, 0x54, 0x5D, 0x4E, 0x4C, 0x39, 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F,
370 0x47, 0x43, 0x69, 0x48, 0x33, 0x51, 0x54, 0x5D, 0x6E, 0x3C, 0x31, 0x64, 0x35, 0x5A, 0x00, 0x00 };
375 return val_to_str(num, msgTypeCode, "Unknown");
381 return val_to_str(num, serverMetaSubCmdCode, "Unknown (0x%04x)");
385 findClientCmd(int num)
387 return val_to_str(num, clientCmdCode, "Unknown (%u)");
391 findServerCmd(int num)
393 return val_to_str(num, serverCmdCode, "Unknown (%u)");
399 return val_to_str(num, statusCode, "Unknown (0x%08x)");
403 get_v5key(tvbuff_t *tvb, int len)
405 guint32 a1, a2, a3, a4, a5;
406 guint32 code, check, key;
408 code = tvb_get_letohl(tvb, ICQ5_CL_CHECKCODE);
410 a1 = code & 0x0001f000;
411 a2 = code & 0x07c007c0;
412 a3 = code & 0x003e0001;
413 a4 = code & 0xf8000000;
414 a5 = code & 0x0000083e;
422 check = a5 + a1 + a2 + a3 + a4;
423 key = len * 0x68656C6C;
429 decrypt_v5(guchar *bfr, guint32 size,guint32 key)
434 for (i=ICQ5_CL_SESSIONID; i < size; i+=4 ) {
435 k = key+table_v5[i&0xff];
437 bfr[i] ^= (guchar)(k & 0xff);
438 bfr[i+1] ^= (guchar)((k & 0xff00)>>8);
441 bfr[i+2] ^= (guchar)((k & 0xff0000)>>16);
442 bfr[i+3] ^= (guchar)((k & 0xff000000)>>24);
448 dissect_icqv4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
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, proto_icq, tvb, 0, -1,
463 icq_tree = proto_item_add_subtree(ti, ett_icq);
465 proto_tree_add_text(icq_tree, tvb, ICQ_VERSION, 2, "Version: %u",
466 tvb_get_letohs(tvb, ICQ_VERSION));
471 dissect_icqv3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
473 proto_tree *icq_tree = NULL;
474 proto_item *ti = NULL;
476 /* Not really implemented yet */
477 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
478 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQv3 (UDP)");
480 if (check_col(pinfo->cinfo, COL_INFO)) {
481 col_set_str(pinfo->cinfo, COL_INFO, "ICQ Version 3 protocol");
484 ti = proto_tree_add_protocol_format(tree, proto_icq, tvb, 0, -1,
486 icq_tree = proto_item_add_subtree(ti, ett_icq);
488 proto_tree_add_text(icq_tree, tvb, ICQ_VERSION, 2, "Version: %u",
489 tvb_get_letohs(tvb, ICQ_VERSION));
494 dissect_icqv2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
496 proto_tree *icq_tree = NULL;
497 proto_item *ti = NULL;
499 /* Not really implemented yet */
500 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
501 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQv2 (UDP)");
503 if (check_col(pinfo->cinfo, COL_INFO)) {
504 col_set_str(pinfo->cinfo, COL_INFO, "ICQ Version 2 protocol");
507 ti = proto_tree_add_protocol_format(tree, proto_icq, tvb, 0, -1,
509 icq_tree = proto_item_add_subtree(ti, ett_icq);
511 proto_tree_add_text(icq_tree, tvb, ICQ_VERSION, 2, "Version: %u",
512 tvb_get_letohs(tvb, ICQ_VERSION));
517 * The packet has, at offset "offset" a (len, string) pair.
518 * Display the length and string in the tree.
520 * If anything is wrong, return -1, since -1 is not a valid string
521 * length. Else, return the number of chars processed.
524 proto_add_icq_attr(proto_tree* tree, /* The tree to add to */
525 tvbuff_t *tvb, /* Tvbuff with packet */
526 const int offset, /* Offset from the start of packet of field */
527 const char* descr) /* The description to use in the tree */
531 len = tvb_get_letohs(tvb, offset);
532 if (len > tvb_reported_length_remaining(tvb, offset))
533 return -1; /* length goes past end of packet */
534 proto_tree_add_text(tree, tvb, offset, sizeof(guint16) + len,
535 "%s[%u]: %.*s", descr, len, len,
536 tvb_get_ptr(tvb, offset + sizeof(guint16), len));
537 return len + sizeof(guint16);
541 icqv5_decode_msgType(proto_tree* tree, tvbuff_t *tvb, int offset, int size,
544 proto_item* ti = NULL;
545 proto_tree* subtree = NULL;
549 int sz; /* Size of the current element */
551 static const char* url_field_descr[] = {
555 #define N_URL_FIELDS (sizeof url_field_descr / sizeof url_field_descr[0])
556 static const char* email_field_descr[] = {
564 #define N_EMAIL_FIELDS (sizeof email_field_descr / sizeof email_field_descr[0])
565 static const char* auth_req_field_descr[] = {
573 #define N_AUTH_REQ_FIELDS (sizeof auth_req_field_descr / sizeof auth_req_field_descr[0])
574 static const char* user_added_field_descr[] = {
580 #define N_USER_ADDED_FIELDS (sizeof user_added_field_descr / sizeof user_added_field_descr[0])
582 msgType = tvb_get_letohs(tvb, offset);
583 ti = proto_tree_add_text(tree, tvb, offset, size,
584 "Message: Type = %u (%s)", msgType, findMsgType(msgType));
585 /* Create a new subtree */
586 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
588 proto_tree_add_text(subtree, tvb, offset, 2,
589 "Type: %u (%s)", msgType, findMsgType(msgType));
592 if (msgType != MSG_AUTH) {
594 * XXX - does a MSG_AUTH message really have 3 bytes of information
595 * rather than a length field?
597 proto_tree_add_text(subtree, tvb, offset, 2, "Length: %u",
598 tvb_get_letohs(tvb, offset));
604 case 0xffff: /* Field unknown */
607 expert_add_info_format(pinfo, NULL, PI_UNDECODED, PI_WARN,
608 "Unknown msgType: %u (0x%x)", msgType,
612 proto_tree_add_text(subtree, tvb, offset, left, "Msg: %.*s", left-1,
613 tvb_get_ptr(tvb, offset, left));
616 for (n = 0; n < N_URL_FIELDS; n++) {
617 if (n != N_URL_FIELDS - 1) {
618 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
619 sz = sep_offset - offset + 1;
623 proto_tree_add_text(subtree, tvb, offset, sz, "%s: %.*s",
626 tvb_get_ptr(tvb, offset, sz));
628 proto_tree_add_text(subtree, tvb, offset, 0,
629 "%s: %s", url_field_descr[n], "(empty)");
636 for (n = 0; n < N_EMAIL_FIELDS; n++) {
637 if (n != N_EMAIL_FIELDS - 1) {
638 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
639 sz = sep_offset - offset + 1;
643 proto_tree_add_text(subtree, tvb, offset, sz, "%s: %.*s",
644 email_field_descr[n],
646 tvb_get_ptr(tvb, offset, sz));
648 proto_tree_add_text(subtree, tvb, offset, 0, "%s: %s",
649 email_field_descr[n], "(empty)");
658 /* Three bytes, first is a char signifying success */
659 unsigned char auth_suc;
661 auth_suc = tvb_get_guint8(tvb, offset);
662 proto_tree_add_text(subtree, tvb, offset, 1,
663 "Authorization: (%u) %s",auth_suc,
664 (auth_suc==0)?"Denied":"Allowed");
666 proto_tree_add_text(subtree, tvb, offset, sizeof(guint16), "x1: 0x%04x",
667 tvb_get_letohs(tvb, offset));
671 for (n = 0; n < N_AUTH_REQ_FIELDS; n++) {
672 if (n != N_AUTH_REQ_FIELDS - 1) {
673 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
674 sz = sep_offset - offset + 1;
678 proto_tree_add_text(subtree, tvb, offset, sz, "%s: %.*s",
679 auth_req_field_descr[n], sz - 1,
680 tvb_get_ptr(tvb, offset, sz));
682 proto_tree_add_text(subtree, tvb, offset, 0, "%s: %s",
683 auth_req_field_descr[n], "(empty)");
690 for (n = 0; n < N_USER_ADDED_FIELDS; n++) {
691 if (n != N_USER_ADDED_FIELDS - 1) {
692 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
693 sz = sep_offset - offset + 1;
697 proto_tree_add_text(subtree, tvb, offset, sz, "%s: %.*s",
698 user_added_field_descr[n], sz - 1,
699 tvb_get_ptr(tvb, offset, sz));
701 proto_tree_add_text(subtree, tvb, offset, 0, "%s: %s",
702 user_added_field_descr[n], "(empty)");
710 gint sep_offset_prev;
711 int sz_local = 0; /* Size of the current element */
712 int n_local = 0; /* The nth element */
713 gboolean last = FALSE;
716 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
717 if (sep_offset != -1)
718 sz_local = sep_offset - offset + 1;
724 /* The first element is the number of Nick/UIN pairs follow */
725 proto_tree_add_text(subtree, tvb, offset, sz_local,
726 "Number of pairs: %.*s", sz_local - 1,
727 tvb_get_ptr(tvb, offset, sz_local));
733 sep_offset_prev = sep_offset;
734 sep_offset = tvb_find_guint8(tvb, sep_offset_prev, left, 0xfe);
735 if (sep_offset != -1)
736 sz_local = sep_offset - offset + 1;
741 proto_tree_add_text(subtree, tvb, offset, sz_local + svsz,
742 "%.*s: %.*s", svsz - 1,
743 tvb_get_ptr(tvb, offset, svsz), sz_local - 1,
744 tvb_get_ptr(tvb, sep_offset_prev + 1, sz_local));
748 left -= (sz_local+1);
749 offset = sep_offset + 1;
756 /*********************************
760 *********************************/
762 icqv5_cmd_ack(proto_tree* tree,/* Tree to put the data in */
763 tvbuff_t *tvb, /* Tvbuff with decrypted packet data */
764 int offset) /* Offset from the start of the packet to the content */
770 ti = proto_tree_add_text(tree, tvb, offset, 4, "Body");
771 subtree = proto_item_add_subtree(ti, ett_icq_body);
772 proto_tree_add_text(subtree, tvb, offset + CMD_ACK_RANDOM, 4,
774 tvb_get_letohl(tvb, offset + CMD_ACK_RANDOM));
779 icqv5_cmd_rand_search(proto_tree* tree, /* Tree to put the data in */
780 tvbuff_t *tvb, /* Decrypted packet content */
781 int offset, /* Offset from the start of the packet to the content */
782 int size) /* Number of chars left to do */
788 static const char* groups[] = {
804 ti = proto_tree_add_text(tree, tvb, offset, size,
805 "Body (%d bytes, should be 4)", size);
808 ti = proto_tree_add_text(tree, tvb, offset, 4, "Body");
809 subtree = proto_item_add_subtree(ti, ett_icq_body);
810 group = tvb_get_letohs(tvb, offset + CMD_RAND_SEARCH_GROUP);
811 if (group>0 && (group<=sizeof(groups)/sizeof(const char*)))
812 proto_tree_add_text(subtree, tvb, offset + CMD_RAND_SEARCH_GROUP,
813 4, "Group: (%u) %s", group, groups[group-1]);
815 proto_tree_add_text(subtree, tvb, offset + CMD_RAND_SEARCH_GROUP,
816 4, "Group: (%u)", group);
821 icqv5_cmd_ack_messages(proto_tree* tree, /* Tree to put the data in */
822 tvbuff_t *tvb, /* Decrypted packet content */
823 int offset) /* Offset from the start of the packet to the content */
829 ti = proto_tree_add_text(tree, tvb, offset, 4, "Body");
830 subtree = proto_item_add_subtree(ti, ett_icq_body);
831 proto_tree_add_text(subtree, tvb, offset + CMD_ACK_MESSAGES_RANDOM,
833 tvb_get_letohl(tvb, offset + CMD_ACK_MESSAGES_RANDOM));
838 icqv5_cmd_keep_alive(proto_tree* tree, /* Tree to put the data in */
839 tvbuff_t *tvb, /* Decrypted packet content */
840 int offset) /* Offset from the start of the packet to the content */
847 ti = proto_tree_add_text(tree, tvb, offset, 4, "Body");
848 subtree = proto_item_add_subtree(ti, ett_icq_body);
849 randomx = tvb_get_letohl(tvb, offset + CMD_KEEP_ALIVE_RANDOM);
850 proto_tree_add_text(subtree, tvb, offset + CMD_KEEP_ALIVE_RANDOM,
851 4, "Random: 0x%08x", randomx);
856 icqv5_cmd_send_text_code(proto_tree* tree, /* Tree to put the data in */
857 tvbuff_t *tvb, /* Decrypted packet content */
858 int offset, /* Offset from the start of the packet to the content */
859 int size) /* Number of chars left to do */
861 proto_tree* subtree = NULL;
862 proto_item* ti = NULL;
867 ti = proto_tree_add_text(tree, tvb, offset, size, "Body");
870 len = tvb_get_letohs(tvb, offset+CMD_SEND_TEXT_CODE_LEN);
872 subtree = proto_item_add_subtree(ti, ett_icq_body);
873 proto_tree_add_text(subtree, tvb, offset + CMD_SEND_TEXT_CODE_LEN,
874 2, "Length: %d", len);
879 proto_tree_add_text(subtree, tvb, offset + CMD_SEND_TEXT_CODE_TEXT,
880 len, "Text: %.*s", len,
881 tvb_get_ptr(tvb, offset + CMD_SEND_TEXT_CODE_TEXT,
886 x1 = tvb_get_letohs(tvb, offset + CMD_SEND_TEXT_CODE_TEXT + len);
888 proto_tree_add_text(subtree, tvb,
889 offset + CMD_SEND_TEXT_CODE_TEXT + len,
890 2, "X1: 0x%04x", x1);
895 icqv5_cmd_add_to_list(proto_tree* tree, /* Tree to put the data in */
896 tvbuff_t *tvb, /* Decrypted packet content */
897 int offset) /* Offset from the start of the packet to the content */
904 ti = proto_tree_add_text(tree, tvb, offset, 4, "Body");
905 subtree = proto_item_add_subtree(ti, ett_icq_body);
906 uin = tvb_get_letohl(tvb, offset + CMD_ADD_TO_LIST);
907 proto_tree_add_text(subtree, tvb, offset + CMD_ADD_TO_LIST_UIN, 4,
913 icqv5_cmd_status_change(proto_tree* tree, /* Tree to put the data in */
914 tvbuff_t *tvb, /* Decrypted packet content */
915 int offset) /* Offset from the start of the packet to the content */
922 ti = proto_tree_add_text(tree, tvb, offset, 4, "Body");
923 subtree = proto_item_add_subtree(ti, ett_icq_body);
924 status = tvb_get_letohl(tvb, offset + CMD_STATUS_CHANGE_STATUS);
925 proto_tree_add_text(subtree, tvb, offset + CMD_STATUS_CHANGE_STATUS,
926 4, "Status: %s", findStatus(status));
931 icqv5_cmd_send_msg(proto_tree* tree, tvbuff_t *tvb, int offset, int size,
936 int left = size; /* left chars to do */
940 ti = proto_tree_add_text(tree, tvb, offset, size,
941 "Body (%d bytes, should be >= 4)", size);
944 ti = proto_tree_add_text(tree, tvb, offset, size, "Body");
945 subtree = proto_item_add_subtree(ti, ett_icq_body);
946 proto_tree_add_text(subtree, tvb, offset + CMD_SEND_MSG_RECV_UIN, 4,
948 tvb_get_letohl(tvb, offset + CMD_SEND_MSG_RECV_UIN));
951 icqv5_decode_msgType(subtree, tvb, offset + CMD_SEND_MSG_MSG_TYPE,
957 icqv5_cmd_login(proto_tree* tree, tvbuff_t *tvb, int offset, int size)
965 const guchar *ipAddrp;
969 ti = proto_tree_add_text(tree, tvb, offset, size, "Body");
970 subtree = proto_item_add_subtree(ti, ett_icq_body);
971 theTime = tvb_get_letohl(tvb, offset + CMD_LOGIN_TIME);
972 aTime = ctime(&theTime);
973 aTime[strlen(aTime)-1] = '\0';
974 proto_tree_add_text(subtree, tvb, offset + CMD_LOGIN_TIME, 4,
975 "Time: %ld = %s", (long)theTime, aTime);
976 port = tvb_get_letohl(tvb, offset + CMD_LOGIN_PORT);
977 proto_tree_add_text(subtree, tvb, offset + CMD_LOGIN_PORT, 4,
979 passwdLen = tvb_get_letohs(tvb, offset + CMD_LOGIN_PASSLEN);
980 proto_tree_add_text(subtree, tvb, offset + CMD_LOGIN_PASSLEN,
981 2 + passwdLen, "Passwd: %.*s", (int)passwdLen,
982 tvb_get_ptr(tvb, offset + CMD_LOGIN_PASSWD,
984 ipAddrp = tvb_get_ptr(tvb,
985 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP,
987 proto_tree_add_text(subtree, tvb,
988 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP,
989 4, "IP: %s", ip_to_str(ipAddrp));
990 status = tvb_get_letohs(tvb,
991 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS);
992 proto_tree_add_text(subtree, tvb,
993 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS,
994 4, "Status: %s", findStatus(status));
999 icqv5_cmd_contact_list(proto_tree* tree, tvbuff_t *tvb, int offset, int size)
1001 proto_tree* subtree;
1008 ti = proto_tree_add_text(tree, tvb, offset, size, "Body");
1009 subtree = proto_item_add_subtree(ti, ett_icq_body);
1010 num = tvb_get_guint8(tvb, offset + CMD_CONTACT_LIST_NUM);
1011 proto_tree_add_text(subtree, tvb, offset + CMD_CONTACT_LIST,
1012 1, "Number of uins: %u", num);
1014 * A sequence of num times UIN follows
1016 offset += (CMD_CONTACT_LIST_NUM + 1);
1017 for (i = 0; i < num; i++) {
1018 uin = tvb_get_letohl(tvb, offset);
1019 proto_tree_add_text(subtree, tvb, offset, 4,
1020 "UIN[%d]: %u", i ,uin);
1027 icqv5_cmd_no_params(proto_tree* tree, /* Tree to put the data in */
1028 tvbuff_t *tvb, /* Decrypted packet content */
1029 int offset) /* Offset from the start of the packet to the content */
1031 proto_tree* subtree;
1035 ti = proto_tree_add_text(tree, tvb, offset, 0, "Body");
1036 subtree = proto_item_add_subtree(ti, ett_icq_body);
1037 proto_tree_add_text(subtree, tvb, offset, 0, "No parameters");
1041 /**********************
1045 **********************
1048 icqv5_srv_no_params(proto_tree* tree, /* Tree to put the data in */
1049 tvbuff_t *tvb, /* Packet content */
1050 int offset) /* Offset from the start of the packet to the content */
1052 proto_tree* subtree;
1056 ti = proto_tree_add_text(tree, tvb, offset, 0, "Body");
1057 subtree = proto_item_add_subtree(ti, ett_icq_body);
1058 proto_tree_add_text(subtree, tvb, offset, 0, "No Parameters");
1063 icqv5_srv_login_reply(proto_tree* tree,/* Tree to put the data in */
1064 tvbuff_t *tvb, /* Tvbuff with packet */
1065 int offset, /* Offset from the start of the packet to the content */
1066 int size) /* Number of chars left to do */
1068 proto_tree* subtree;
1070 const guchar *ipAddrp;
1073 if (size < SRV_LOGIN_REPLY_IP + 8) {
1074 ti = proto_tree_add_text(tree, tvb, offset, size,
1075 "Body (%d bytes, should be %d)", size,
1076 SRV_LOGIN_REPLY_IP + 8);
1079 ti = proto_tree_add_text(tree, tvb, offset, SRV_LOGIN_REPLY_IP + 8,
1081 subtree = proto_item_add_subtree(ti, ett_icq_body);
1082 ipAddrp = tvb_get_ptr(tvb, offset + SRV_LOGIN_REPLY_IP, 4);
1083 proto_tree_add_text(subtree, tvb, offset + SRV_LOGIN_REPLY_IP, 4,
1084 "IP: %s", ip_to_str(ipAddrp));
1089 icqv5_srv_user_online(proto_tree* tree,/* Tree to put the data in */
1090 tvbuff_t *tvb, /* Tvbuff with packet */
1091 int offset, /* Offset from the start of the packet to the content */
1092 int size) /* Number of chars left to do */
1094 proto_tree* subtree;
1096 const guchar *ipAddrp;
1097 const guchar *realipAddrp;
1101 if (size < SRV_LOGIN_REPLY_IP + 8) {
1102 ti = proto_tree_add_text(tree, tvb, offset, size,
1103 "Body (%d bytes, should be %d)", size,
1104 SRV_LOGIN_REPLY_IP + 8);
1107 ti = proto_tree_add_text(tree, tvb, offset, SRV_LOGIN_REPLY_IP + 8,
1109 subtree = proto_item_add_subtree(ti, ett_icq_body);
1110 proto_tree_add_text(subtree, tvb, offset + SRV_USER_ONL_UIN, 4,
1112 tvb_get_letohl(tvb, offset + SRV_USER_ONL_UIN));
1113 ipAddrp = tvb_get_ptr(tvb, offset + SRV_USER_ONL_IP, 4);
1114 proto_tree_add_text(subtree, tvb, offset + SRV_USER_ONL_IP, 4,
1115 "IP: %s", ip_to_str(ipAddrp));
1116 proto_tree_add_text(subtree, tvb, offset + SRV_USER_ONL_PORT, 4,
1118 tvb_get_letohl(tvb, offset + SRV_USER_ONL_PORT));
1119 realipAddrp = tvb_get_ptr(tvb, offset + SRV_USER_ONL_REALIP, 4);
1120 proto_tree_add_text(subtree, tvb, offset + SRV_USER_ONL_REALIP, 4,
1121 "RealIP: %s", ip_to_str(realipAddrp));
1122 status = tvb_get_letohs(tvb, offset + SRV_USER_ONL_STATUS);
1123 proto_tree_add_text(subtree, tvb, offset + SRV_USER_ONL_STATUS, 2,
1124 "Status: %s", findStatus(status));
1126 * Kojak: Hypothesis is that this field might be an encoding for the
1127 * version used by the UIN that changed. To test this, I included
1128 * this line to the code.
1130 proto_tree_add_text(subtree, tvb, offset + SRV_USER_ONL_X2, 4,
1132 tvb_get_letohl(tvb, offset + SRV_USER_ONL_X2));
1137 icqv5_srv_user_offline(proto_tree* tree,/* Tree to put the data in */
1138 tvbuff_t *tvb, /* Tvbuff with packet */
1139 int offset, /* Offset from the start of the packet to the content */
1140 int size) /* Number of chars left to do */
1142 proto_tree* subtree;
1146 if (size < SRV_USER_OFFLINE_UIN + 4) {
1147 ti = proto_tree_add_text(tree, tvb, offset, size,
1148 "Body (%d bytes, should be %d)", size,
1149 SRV_USER_OFFLINE_UIN + 4);
1152 ti = proto_tree_add_text(tree, tvb, offset, SRV_USER_OFFLINE_UIN + 4,
1154 subtree = proto_item_add_subtree(ti, ett_icq_body);
1155 proto_tree_add_text(subtree, tvb, offset + SRV_USER_OFFLINE_UIN, 4,
1157 tvb_get_letohl(tvb, offset + SRV_USER_OFFLINE));
1162 icqv5_srv_multi(proto_tree* tree, /* Tree to put the data in */
1163 tvbuff_t *tvb, /* Packet content */
1164 int offset, /* Offset from the start of the packet to the content */
1165 int size, /* Number of chars left to do */
1168 proto_tree* subtree;
1175 ti = proto_tree_add_text(tree, tvb, offset, size, "Body");
1176 subtree = proto_item_add_subtree(ti, ett_icq_body);
1177 num = tvb_get_guint8(tvb, offset + SRV_MULTI_NUM);
1178 proto_tree_add_text(subtree, tvb, offset + SRV_MULTI_NUM, 1,
1179 "Number of pkts: %u", num);
1181 * A sequence of num times ( pktsize, packetData) follows
1183 offset += (SRV_MULTI_NUM + 1);
1184 for (i = 0; i < num; i++) {
1185 pktSz = tvb_get_letohs(tvb, offset);
1187 dissect_icqv5Server(tvb, offset, pinfo, subtree, pktSz);
1194 icqv5_srv_meta_user(proto_tree* tree, /* Tree to put the data in */
1195 tvbuff_t *tvb, /* Tvbuff with packet */
1196 int offset, /* Offset from the start of the packet to the content */
1197 int size, /* Number of chars left to do */
1201 proto_tree* subtree = NULL;
1203 proto_tree* sstree = NULL;
1204 proto_item* ti = NULL;
1207 unsigned char result;
1211 ti = proto_tree_add_text(tree, tvb, offset, size, "Body");
1212 subtree = proto_item_add_subtree(ti, ett_icq_body);
1213 subcmd = tvb_get_letohs(tvb, offset + SRV_META_USER_SUBCMD);
1214 ti = proto_tree_add_text(subtree, tvb, offset + SRV_META_USER_SUBCMD,
1215 2, "%s", findSubCmd(subcmd));
1216 result = tvb_get_guint8(tvb, offset + SRV_META_USER_RESULT);
1217 proto_tree_add_text(subtree, tvb, offset + SRV_META_USER_RESULT, 1,
1218 "%s", (result==0x0a)?"Success":"Failure");
1219 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1221 subcmd = tvb_get_letohs(tvb, offset + SRV_META_USER_SUBCMD);
1222 ti = proto_tree_add_text(tree, tvb, offset + SRV_META_USER_SUBCMD,
1223 2, "%s", findSubCmd(subcmd));
1224 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1225 result = tvb_get_guint8(tvb, offset + SRV_META_USER_RESULT);
1226 proto_tree_add_text(sstree, tvb, offset + SRV_META_USER_RESULT,
1227 1, "%s", (result==0x0a)?"Success":"Failure");
1230 /* Skip the META_USER header */
1235 case META_EX_USER_FOUND:
1237 /* This is almost the same as META_USER_FOUND,
1238 * however, there's an extra length field
1242 /* Read the length field */
1243 pktLen = tvb_get_letohs(tvb, offset);
1244 proto_tree_add_text(sstree, tvb, offset, sizeof(guint16),
1245 "Length: %u", pktLen);
1247 offset += sizeof(guint16); left -= sizeof(guint16);
1249 case META_USER_FOUND:
1251 /* The goto mentioned in this block should be local to this
1252 * block if C'd allow it.
1254 * They are used to "implement" a poorman's exception handling
1257 const char *descr[] = {
1263 const char** d = descr;
1268 proto_tree_add_text(sstree, tvb, offset, sizeof(guint32),
1269 "UIN: %u", tvb_get_letohl(tvb, offset));
1270 offset+=sizeof(guint32);left-=sizeof(guint32);
1272 for ( ; *d!=NULL; d++) {
1273 len = proto_add_icq_attr(sstree, tvb, offset, *d);
1276 offset += len; left -= len;
1278 /* Get the authorize setting */
1279 auth = tvb_get_guint8(tvb, offset);
1280 proto_tree_add_text(sstree, tvb, offset, 1,
1281 "authorization: %s", (auth==0x01)?"Necessary":"Who needs it");
1284 proto_tree_add_text(sstree, tvb, offset, sizeof(guint16),
1285 "x2: 0x%04x", tvb_get_letohs(tvb, offset));
1286 offset+=sizeof(guint16);left-=sizeof(guint16);
1288 proto_tree_add_text(sstree, tvb, offset, sizeof(guint32),
1289 "x3: 0x%08x", tvb_get_letohl(tvb, offset));
1290 offset+=sizeof(guint32);left-=sizeof(guint32);
1297 /* Get the about information */
1298 len = tvb_get_letohs(tvb, offset);
1299 offset+=sizeof(guint16);left-=sizeof(guint16);
1300 proto_tree_add_text(sstree, tvb, offset - sizeof(guint16),
1301 sizeof(guint16)+len, "About(%d): %.*s", len,
1302 len, tvb_get_ptr(tvb, offset, len));
1303 offset+=len;left-=len;
1306 case META_USER_INFO:
1308 /* The goto mentioned in this block should be local to this
1309 * block if C'd allow it.
1311 * They are used to "implement" a poorman's exception handling
1313 static const char* descr[] = {
1328 const char** d = descr;
1330 guint8 user_timezone;
1335 uin = tvb_get_letohl(tvb, offset);
1336 proto_tree_add_text(sstree, tvb, offset, sizeof(guint32),
1338 offset+=sizeof(guint32);left-=sizeof(guint32);
1342 * Get every field from the description
1344 while ((*d)!=NULL) {
1345 len = tvb_get_letohs(tvb, offset);
1346 offset+=sizeof(guint16);left-=sizeof(guint16);
1348 proto_tree_add_text(sstree, tvb, offset - sizeof(guint16),
1349 sizeof(guint16)+len, "%s(%d): %.*s",
1351 tvb_get_ptr(tvb, offset, len - 1));
1352 offset+=len;left-=len;
1356 /* Get country code */
1357 country = tvb_get_letohs(tvb, offset);
1358 proto_tree_add_text(sstree, tvb, offset, sizeof(guint16),
1359 "Countrycode: %u", country);
1360 offset+=sizeof(guint16); left-=sizeof(guint16);
1361 /* Get the timezone setting */
1362 user_timezone = tvb_get_guint8(tvb, offset);
1363 proto_tree_add_text(sstree, tvb, offset, sizeof(unsigned char),
1364 "Timezone: %u", user_timezone);
1366 /* Get the authorize setting */
1367 auth = tvb_get_guint8(tvb, offset);
1368 proto_tree_add_text(sstree, tvb, offset, sizeof(unsigned char),
1369 "Authorization: (%u) %s", auth,
1370 (auth==0)?"No":"Yes");
1372 /* Get the webaware setting */
1373 auth = tvb_get_guint8(tvb, offset);
1374 proto_tree_add_text(sstree, tvb, offset, sizeof(unsigned char),
1375 "Webaware: (%u) %s", auth,
1376 (auth==0)?"No":"Yes");
1378 /* Get the authorize setting */
1379 auth = tvb_get_guint8(tvb, offset);
1380 proto_tree_add_text(sstree, tvb, offset, sizeof(unsigned char),
1381 "HideIP: (%u) %s", auth, (auth==0)?"No":"Yes");
1386 /* This information is already printed in the tree */
1387 expert_add_info_format(pinfo, NULL, PI_UNDECODED, PI_WARN,
1388 "Meta subcmd: 0x%x", subcmd);
1395 icqv5_srv_recv_message(proto_tree* tree, /* Tree to put the data in */
1396 tvbuff_t* tvb, /* Packet content */
1397 int offset, /* Offset from the start of the packet to the content */
1398 int size, /* Number of chars left to do */
1401 proto_tree* subtree = NULL;
1402 proto_item* ti = NULL;
1411 ti = proto_tree_add_text(tree, tvb, offset, 4, "Body");
1412 subtree = proto_item_add_subtree(ti, ett_icq_body);
1413 proto_tree_add_item(subtree, hf_icq_uin, tvb, offset + SRV_RECV_MSG_UIN,
1414 sizeof(guint32), TRUE);
1415 year = tvb_get_letohs(tvb, offset + SRV_RECV_MSG_YEAR);
1416 month = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_MONTH);
1417 day = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_DAY);
1418 hour = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_HOUR);
1419 minute = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_MINUTE);
1421 proto_tree_add_text(subtree, tvb, offset + SRV_RECV_MSG_YEAR,
1422 sizeof(guint16) + 4*sizeof(unsigned char),
1423 "Time: %u-%u-%u %02u:%02u",
1424 day, month, year, hour, minute);
1425 icqv5_decode_msgType(subtree, tvb, offset + SRV_RECV_MSG_MSG_TYPE,
1431 icqv5_srv_rand_user(proto_tree* tree, /* Tree to put the data in */
1432 tvbuff_t *tvb, /* Tvbuff with packet */
1433 int offset) /* Offset from the start of the packet to the content */
1435 proto_tree* subtree = NULL;
1436 proto_item* ti = NULL;
1438 const unsigned char* IP = NULL;
1440 const unsigned char* realIP = NULL;
1446 ti = proto_tree_add_text(tree, tvb, offset, SRV_RAND_USER_TCP_VER + 2,
1448 subtree = proto_item_add_subtree(ti, ett_icq_body);
1450 uin = tvb_get_letohl(tvb, offset + SRV_RAND_USER_UIN);
1451 proto_tree_add_text(subtree, tvb, offset + SRV_RAND_USER_UIN,
1452 sizeof(guint32), "UIN: %u", uin);
1454 IP = tvb_get_ptr(tvb, offset + SRV_RAND_USER_IP, 4);
1455 proto_tree_add_text(subtree, tvb, offset + SRV_RAND_USER_IP,
1456 sizeof(guint32), "IP: %s", ip_to_str(IP));
1457 /* guint16 portNum */
1458 /* XXX - 16 bits, or 32 bits? */
1459 port = tvb_get_letohs(tvb, offset + SRV_RAND_USER_PORT);
1460 proto_tree_add_text(subtree, tvb, offset + SRV_RAND_USER_UIN,
1461 sizeof(guint32), "Port: %u", port);
1462 /* guint32 realIP */
1463 realIP = tvb_get_ptr(tvb, offset + SRV_RAND_USER_REAL_IP, 4);
1464 proto_tree_add_text(subtree, tvb, offset + SRV_RAND_USER_REAL_IP,
1465 sizeof(guint32), "RealIP: %s", ip_to_str(realIP));
1466 /* guint8 Communication Class */
1467 commClass = tvb_get_guint8(tvb, offset + SRV_RAND_USER_CLASS);
1468 proto_tree_add_text(subtree, tvb, offset + SRV_RAND_USER_CLASS,
1469 sizeof(guint8), "Class: %s",
1470 (commClass!=4)?"User to User":"Through Server");
1471 /* guint32 status */
1472 /* XXX - 16 bits, or 32 bits? */
1473 status = tvb_get_letohs(tvb, offset + SRV_RAND_USER_STATUS);
1474 proto_tree_add_text(subtree, tvb, offset + SRV_RAND_USER_STATUS,
1475 sizeof(guint32), "Status: %s", findStatus(status));
1476 /* guint16 tcpVersion */
1477 tcpVer = tvb_get_letohs(tvb, offset + SRV_RAND_USER_TCP_VER);
1478 proto_tree_add_text(subtree, tvb, offset + SRV_RAND_USER_TCP_VER,
1479 sizeof(guint16), "TCPVersion: %u", tcpVer);
1484 * Dissect all the v5 client traffic. This is encrypted, so be careful.
1487 dissect_icqv5Client(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1489 proto_tree *icq_tree = NULL;
1490 proto_tree *icq_header_tree = NULL;
1491 proto_item *ti = NULL;
1493 int pktsize; /* The actual size of the ICQ content */
1494 int capturedsize; /* The captured size of the ICQ content */
1495 guint32 rounded_size;
1498 guint8 *decr_pd; /* Decrypted content */
1501 pktsize = tvb_reported_length(tvb);
1502 capturedsize = tvb_length(tvb);
1504 /* Get the encryption key */
1505 key = get_v5key(tvb, pktsize);
1508 * Make a copy of the packet data, and decrypt it.
1509 * The decryption processes 4 bytes at a time, and starts at
1510 * an offset of ICQ5_CL_SESSIONID (which isn't a multiple of 4),
1511 * so we make sure that there are
1513 * (ICQ5_CL_SESSIONID + a multiple of 4)
1515 * bytes in the buffer.
1517 rounded_size = ((((capturedsize - ICQ5_CL_SESSIONID) + 3)/4)*4) + ICQ5_CL_SESSIONID;
1518 decr_pd = g_malloc(rounded_size);
1519 tvb_memcpy(tvb, decr_pd, 0, capturedsize);
1520 decrypt_v5(decr_pd, rounded_size, key);
1522 /* Allocate a new tvbuff, referring to the decrypted data. */
1523 decr_tvb = tvb_new_child_real_data(tvb, decr_pd, capturedsize, pktsize);
1525 /* Arrange that the allocated packet data copy be freed when the
1527 tvb_set_free_cb(decr_tvb, g_free);
1529 /* Add the decrypted data to the data source list. */
1530 add_new_data_source(pinfo, decr_tvb, "Decrypted");
1532 cmd = tvb_get_letohs(decr_tvb, ICQ5_CL_CMD);
1534 if (check_col(pinfo->cinfo, COL_INFO))
1535 col_add_fstr(pinfo->cinfo, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
1538 ti = proto_tree_add_protocol_format(tree, proto_icq, tvb, 0, -1,
1539 "ICQv5 %s (len %u)",
1540 findClientCmd(cmd), pktsize);
1541 icq_tree = proto_item_add_subtree(ti, ett_icq);
1542 ti = proto_tree_add_uint_format(icq_tree, hf_icq_type, tvb, 0,
1543 ICQ5_CL_HDRSIZE, ICQ5_client, "Header");
1544 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
1546 proto_tree_add_text(icq_header_tree, tvb, ICQ_VERSION, 2, "Version: %u",
1547 tvb_get_letohs(tvb, ICQ_VERSION));
1548 proto_tree_add_item(icq_header_tree, hf_icq_uin, tvb, ICQ5_CL_UIN, 4,
1550 proto_tree_add_item(icq_header_tree, hf_icq_sessionid, decr_tvb,
1551 ICQ5_CL_SESSIONID, 4, TRUE);
1552 proto_tree_add_uint_format(icq_header_tree, hf_icq_client_cmd,
1553 decr_tvb, ICQ5_CL_CMD, 2, cmd,
1555 val_to_str(cmd, clientCmdCode, "Unknown"), cmd);
1556 proto_tree_add_text(icq_header_tree, decr_tvb, ICQ5_CL_SEQNUM1, 2,
1557 "Seq Number 1: 0x%04x",
1558 tvb_get_letohs(decr_tvb, ICQ5_CL_SEQNUM1));
1559 proto_tree_add_text(icq_header_tree, decr_tvb, ICQ5_CL_SEQNUM2, 2,
1560 "Seq Number 2: 0x%04x",
1561 tvb_get_letohs(decr_tvb, ICQ5_CL_SEQNUM2));
1562 proto_tree_add_uint_format(icq_header_tree, hf_icq_checkcode, tvb,
1563 ICQ5_CL_CHECKCODE, 4, key, "Key: 0x%08x",
1567 icqv5_cmd_ack(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE);
1570 case CMD_MSG_TO_NEW_USER:
1571 icqv5_cmd_send_msg(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE,
1572 pktsize - ICQ5_CL_HDRSIZE, pinfo);
1574 case CMD_RAND_SEARCH:
1575 icqv5_cmd_rand_search(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE,
1576 pktsize - ICQ5_CL_HDRSIZE);
1579 icqv5_cmd_login(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE,
1580 pktsize - ICQ5_CL_HDRSIZE);
1582 case CMD_SEND_TEXT_CODE:
1583 icqv5_cmd_send_text_code(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE,
1584 pktsize - ICQ5_CL_HDRSIZE);
1586 case CMD_STATUS_CHANGE:
1587 icqv5_cmd_status_change(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE);
1589 case CMD_ACK_MESSAGES:
1590 icqv5_cmd_ack_messages(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE);
1592 case CMD_KEEP_ALIVE:
1593 icqv5_cmd_keep_alive(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE);
1595 case CMD_ADD_TO_LIST:
1596 icqv5_cmd_add_to_list(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE);
1598 case CMD_CONTACT_LIST:
1599 icqv5_cmd_contact_list(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE,
1600 pktsize - ICQ5_CL_HDRSIZE);
1603 case CMD_REG_NEW_USER:
1604 case CMD_QUERY_SERVERS:
1605 case CMD_QUERY_ADDONS:
1606 icqv5_cmd_no_params(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE);
1609 proto_tree_add_text(icq_tree, decr_tvb, ICQ5_CL_HDRSIZE,
1610 pktsize - ICQ5_CL_HDRSIZE, "Body");
1611 expert_add_info_format(pinfo, NULL, PI_UNDECODED, PI_WARN,
1612 "Missing: %s", findClientCmd(cmd));
1619 dissect_icqv5Server(tvbuff_t *tvb, int offset, packet_info *pinfo,
1620 proto_tree *tree, int pktsize)
1622 /* Server traffic is easy, not encrypted */
1623 proto_tree *icq_tree = NULL;
1624 proto_tree *icq_header_tree = NULL;
1625 proto_item *ti = NULL;
1626 int changeCol = (pktsize==-1);
1630 cmd = tvb_get_letohs(tvb, offset + ICQ5_SRV_CMD);
1631 if (changeCol && check_col(pinfo->cinfo, COL_INFO))
1632 col_add_fstr(pinfo->cinfo, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
1635 pktsize = tvb_reported_length(tvb);
1638 ti = proto_tree_add_protocol_format(tree, proto_icq, tvb, offset,
1639 pktsize, "ICQv5 %s (len %u)",
1640 findServerCmd(cmd), pktsize);
1642 icq_tree = proto_item_add_subtree(ti, ett_icq);
1644 ti = proto_tree_add_uint_format(icq_tree, hf_icq_type, tvb, offset,
1645 ICQ5_SRV_HDRSIZE, ICQ5_server,
1647 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
1649 proto_tree_add_text(icq_header_tree, tvb, offset + ICQ_VERSION, 2,
1650 "Version: %u", tvb_get_letohs(tvb, ICQ_VERSION));
1651 proto_tree_add_item(icq_header_tree, hf_icq_sessionid, tvb,
1652 offset + ICQ5_SRV_SESSIONID, 4, TRUE);
1653 proto_tree_add_uint_format(icq_header_tree, hf_icq_server_cmd, tvb,
1654 offset + ICQ5_SRV_CMD, 2, cmd, "Command: %s (%u)",
1655 val_to_str(cmd, serverCmdCode, "Unknown"), cmd);
1656 proto_tree_add_text(icq_header_tree, tvb, offset + ICQ5_SRV_SEQNUM1, 2,
1657 "Seq Number 1: 0x%04x",
1658 tvb_get_letohs(tvb, offset + ICQ5_SRV_SEQNUM1));
1659 proto_tree_add_text(icq_header_tree, tvb, offset + ICQ5_SRV_SEQNUM2, 2,
1660 "Seq Number 2: 0x%04x",
1661 tvb_get_letohs(tvb, offset + ICQ5_SRV_SEQNUM2));
1662 proto_tree_add_item(icq_header_tree, hf_icq_uin, tvb,
1663 offset + ICQ5_SRV_UIN, 4, TRUE);
1664 proto_tree_add_item(icq_header_tree, hf_icq_checkcode, tvb,
1665 offset + ICQ5_SRV_CHECKCODE, 4, TRUE);
1668 icqv5_srv_rand_user(icq_tree, tvb, offset + ICQ5_SRV_HDRSIZE);
1670 case SRV_SYS_DELIVERED_MESS:
1671 /* The message structures are all the same. Why not run
1672 * the same routine? */
1673 icqv5_cmd_send_msg(icq_tree, tvb, offset + ICQ5_SRV_HDRSIZE,
1674 pktsize - ICQ5_SRV_HDRSIZE, pinfo);
1676 case SRV_USER_ONLINE:
1677 icqv5_srv_user_online(icq_tree, tvb, offset + ICQ5_SRV_HDRSIZE,
1678 pktsize - ICQ5_SRV_HDRSIZE);
1680 case SRV_USER_OFFLINE:
1681 icqv5_srv_user_offline(icq_tree, tvb, offset + ICQ5_SRV_HDRSIZE,
1682 pktsize - ICQ5_SRV_HDRSIZE);
1684 case SRV_LOGIN_REPLY:
1685 icqv5_srv_login_reply(icq_tree, tvb, offset + ICQ5_SRV_HDRSIZE,
1686 pktsize - ICQ5_SRV_HDRSIZE);
1689 icqv5_srv_meta_user(icq_tree, tvb, offset + ICQ5_SRV_HDRSIZE,
1690 pktsize - ICQ5_SRV_HDRSIZE, pinfo);
1692 case SRV_RECV_MESSAGE:
1693 icqv5_srv_recv_message(icq_tree, tvb, offset + ICQ5_SRV_HDRSIZE,
1694 pktsize - ICQ5_SRV_HDRSIZE, pinfo);
1697 icqv5_srv_multi(icq_tree, tvb, offset + ICQ5_SRV_HDRSIZE,
1698 pktsize - ICQ5_SRV_HDRSIZE, pinfo);
1701 case SRV_SILENT_TOO_LONG:
1705 case SRV_UPDATE_SUCCESS:
1706 icqv5_srv_no_params(icq_tree, tvb, offset + ICQ5_SRV_HDRSIZE);
1709 proto_tree_add_text(icq_tree, tvb, offset + ICQ5_SRV_HDRSIZE,
1710 pktsize - ICQ5_SRV_HDRSIZE, "Body");
1711 expert_add_info_format(pinfo, NULL, PI_UNDECODED, PI_WARN,
1712 "Missing: %s", findClientCmd(cmd));
1718 static void dissect_icqv5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1722 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQv5 (UDP)");
1723 if (check_col(pinfo->cinfo, COL_INFO))
1724 col_set_str(pinfo->cinfo, COL_INFO, "ICQv5 packet");
1726 unknown = tvb_get_letohl(tvb, ICQ5_UNKNOWN);
1728 if (unknown == 0x0L) {
1729 dissect_icqv5Client(tvb, pinfo, tree);
1731 dissect_icqv5Server(tvb, 0, pinfo, tree, -1);
1736 dissect_icq(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1740 version = tvb_get_letohs(tvb, ICQ_VERSION);
1741 if (version < 2 || version > 5)
1742 return 0; /* This is not a (recognized) ICQ packet */
1744 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
1745 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICQ");
1747 if (check_col(pinfo->cinfo, COL_INFO)) {
1748 col_clear(pinfo->cinfo, COL_INFO);
1751 version = tvb_get_letohs(tvb, ICQ_VERSION);
1754 dissect_icqv5(tvb, pinfo, tree);
1757 dissect_icqv4(tvb, pinfo, tree);
1760 dissect_icqv3(tvb, pinfo, tree);
1763 dissect_icqv2(tvb, pinfo, tree);
1766 expert_add_info_format(pinfo, NULL, PI_UNDECODED, PI_WARN,
1767 "Unknown version (0x%x)", version);
1771 return (tvb_length(tvb));
1774 /* registration with the filtering engine */
1776 proto_register_icq(void)
1778 static hf_register_info hf[] = {
1780 {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1782 {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1783 { &hf_icq_sessionid,
1784 {"Session ID", "icq.sessionid", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1785 { &hf_icq_client_cmd,
1786 {"Client command", "icq.client_cmd", FT_UINT16, BASE_HEX, VALS(clientCmdCode), 0x0, NULL, HFILL }},
1787 { &hf_icq_server_cmd,
1788 {"Server command", "icq.server_cmd", FT_UINT16, BASE_DEC, VALS(serverCmdCode), 0x0, NULL, HFILL }},
1789 { &hf_icq_checkcode,
1790 {"Checkcode", "icq.checkcode", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1792 {"Decode", "icq.decode", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}
1794 static gint *ett[] = {
1799 &ett_icq_body_parts,
1802 proto_icq = proto_register_protocol("ICQ Protocol", "ICQ", "icq");
1804 proto_register_field_array(proto_icq, hf, array_length(hf));
1806 proto_register_subtree_array(ett, array_length(ett));
1810 proto_reg_handoff_icq(void)
1812 dissector_handle_t icq_handle;
1814 icq_handle = new_create_dissector_handle(dissect_icq, proto_icq);
1815 dissector_add("udp.port", UDP_PORT_ICQ, icq_handle);