2 * Routines for ICQ packet disassembly
4 * $Id: packet-icq.c,v 1.28 2001/03/27 02:01:31 guy Exp $
6 * Ethereal - Network traffic analyzer
8 * Copyright 1999 Johan Feyaerts
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 * This file: by Kojak <kojak@bigwig.net>
27 * Decoding code ripped, reference to the original author at the
28 * appropriate place with the code itself.
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
39 #ifdef HAVE_NETINET_IN_H
40 #include <netinet/in.h>
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
59 #ifdef NEED_SNPRINTF_H
60 # include "snprintf.h"
66 static int proto_icq = -1;
67 static int hf_icq_uin =-1;
68 static int hf_icq_cmd =-1;
69 static int hf_icq_sessionid =-1;
70 static int hf_icq_checkcode =-1;
71 static int hf_icq_decode = -1;
72 static int hf_icq_type = -1;
74 static gint ett_icq = -1;
75 static gint ett_icq_header = -1;
76 static gint ett_icq_decode = -1;
77 static gint ett_icq_body = -1;
78 static gint ett_icq_body_parts = -1;
80 #define UDP_PORT_ICQ 4000
82 enum { ICQ5_client, ICQ5_server};
84 static void dissect_icqv5(tvbuff_t *tvb,
89 dissect_icqv5Server(tvbuff_t *tvb,
95 /* Offsets of fields in the ICQ headers */
96 /* Can be 0x0002 or 0x0005 */
97 #define ICQ_VERSION 0x00
98 /* Is either one (server) or four (client) bytes long */
99 /* Client header offsets */
100 #define ICQ5_UNKNOWN 0x02
101 #define ICQ5_CL_UIN 0x06
102 #define ICQ5_CL_SESSIONID 0x0a
103 #define ICQ5_CL_CMD 0x0e
104 #define ICQ5_CL_SEQNUM1 0x10
105 #define ICQ5_CL_SEQNUM2 0x12
106 #define ICQ5_CL_CHECKCODE 0x14
107 #define ICQ5_CL_PARAM 0x18
108 #define ICQ5_CL_HDRSIZE 0x18
110 /* Server header offsets */
111 #define ICQ5_SRV_SESSIONID 0x03
112 #define ICQ5_SRV_CMD 0x07
113 #define ICQ5_SRV_SEQNUM1 0x09
114 #define ICQ5_SRV_SEQNUM2 0x0b
115 #define ICQ5_SRV_UIN 0x0d
116 #define ICQ5_SRV_CHECKCODE 0x11
117 #define ICQ5_SRV_PARAM 0x15
118 #define ICQ5_SRV_HDRSIZE 0x15
120 typedef struct _cmdcode {
125 #define SRV_ACK 0x000a
127 #define SRV_SILENT_TOO_LONG 0x001e
129 #define SRV_GO_AWAY 0x0028
131 #define SRV_NEW_UIN 0x0046
133 /* LOGIN_REPLY is very scary. It has a lot of fields that are undocumented
134 * Only the IP field makes sense */
135 #define SRV_LOGIN_REPLY 0x005a
136 #define SRV_LOGIN_REPLY_IP 0x000c
138 #define SRV_BAD_PASS 0x0064
140 #define SRV_USER_ONLINE 0x006e
141 #define SRV_USER_ONL_UIN 0x0000
142 #define SRV_USER_ONL_IP 0x0004
143 #define SRV_USER_ONL_PORT 0x0008
144 #define SRV_USER_ONL_REALIP 0x000c
145 #define SRV_USER_ONL_X1 0x0010
146 #define SRV_USER_ONL_STATUS 0x0013
147 #define SRV_USER_ONL_X2 0x0015
149 #define SRV_USER_OFFLINE 0x0078
150 #define SRV_USER_OFFLINE_UIN 0x0000
152 #define SRV_MULTI 0x0212
153 #define SRV_MULTI_NUM 0x0000
155 #define SRV_META_USER 0x03de
156 #define SRV_META_USER_SUBCMD 0x0000
157 #define SRV_META_USER_RESULT 0x0002
158 #define SRV_META_USER_DATA 0x0003
160 #define SRV_UPDATE_SUCCESS 0x01e0
162 #define SRV_UPDATE_FAIL 0x01ea
165 * ICQv5 SRV_META_USER subcommands
167 #define META_EX_USER_FOUND 0x0190
168 #define META_USER_FOUND 0x019a
169 #define META_ABOUT 0x00e6
170 #define META_USER_INFO 0x00c8
172 #define SRV_RECV_MESSAGE 0x00dc
173 #define SRV_RECV_MSG_UIN 0x0000
174 #define SRV_RECV_MSG_YEAR 0x0004
175 #define SRV_RECV_MSG_MONTH 0x0006
176 #define SRV_RECV_MSG_DAY 0x0007
177 #define SRV_RECV_MSG_HOUR 0x0008
178 #define SRV_RECV_MSG_MINUTE 0x0009
179 #define SRV_RECV_MSG_MSG_TYPE 0x000a
181 #define SRV_RAND_USER 0x024e
182 #define SRV_RAND_USER_UIN 0x0000
183 #define SRV_RAND_USER_IP 0x0004
184 #define SRV_RAND_USER_PORT 0x0008
185 #define SRV_RAND_USER_REAL_IP 0x000c
186 #define SRV_RAND_USER_CLASS 0x0010
187 #define SRV_RAND_USER_X1 0x0011
188 #define SRV_RAND_USER_STATUS 0x0015
189 #define SRV_RAND_USER_TCP_VER 0x0019
191 /* This message has the same structure as cmd_send_msg */
192 #define SRV_SYS_DELIVERED_MESS 0x0104
194 cmdcode serverMetaSubCmdCode[] = {
195 { "META_USER_FOUND", META_USER_FOUND },
196 { "META_EX_USER_FOUND", META_EX_USER_FOUND },
197 { "META_ABOUT", META_ABOUT },
198 { "META_USER_INFO", META_USER_INFO },
202 cmdcode serverCmdCode[] = {
203 { "SRV_ACK", SRV_ACK },
204 { "SRV_SILENT_TOO_LONG", SRV_SILENT_TOO_LONG },
205 { "SRV_GO_AWAY", SRV_GO_AWAY },
206 { "SRV_NEW_UIN", SRV_NEW_UIN },
207 { "SRV_LOGIN_REPLY", SRV_LOGIN_REPLY },
208 { "SRV_BAD_PASS", SRV_BAD_PASS },
209 { "SRV_USER_ONLINE", SRV_USER_ONLINE },
210 { "SRV_USER_OFFLINE", SRV_USER_OFFLINE },
211 { "SRV_QUERY", 130 },
212 { "SRV_USER_FOUND", 140 },
213 { "SRV_END_OF_SEARCH", 160 },
214 { "SRV_NEW_USER", 180 },
215 { "SRV_UPDATE_EXT", 200 },
216 { "SRV_RECV_MESSAGE", SRV_RECV_MESSAGE },
217 { "SRV_END_OFFLINE_MESSAGES", 230 },
218 { "SRV_NOT_CONNECTED", 240 },
219 { "SRV_TRY_AGAIN", 250 },
220 { "SRV_SYS_DELIVERED_MESS", SRV_SYS_DELIVERED_MESS },
221 { "SRV_INFO_REPLY", 280 },
222 { "SRV_EXT_INFO_REPLY", 290 },
223 { "SRV_STATUS_UPDATE", 420 },
224 { "SRV_SYSTEM_MESSAGE", 450 },
225 { "SRV_UPDATE_SUCCESS", SRV_UPDATE_SUCCESS },
226 { "SRV_UPDATE_FAIL", SRV_UPDATE_FAIL },
227 { "SRV_AUTH_UPDATE", 500 },
228 { "SRV_MULTI_PACKET", SRV_MULTI },
229 { "SRV_END_CONTACTLIST_STATUS", 540 },
230 { "SRV_RAND_USER", SRV_RAND_USER },
231 { "SRV_META_USER", SRV_META_USER },
235 #define MSG_TEXT 0x0001
236 #define MSG_URL 0x0004
237 #define MSG_AUTH_REQ 0x0006
238 #define MSG_AUTH 0x0008
239 #define MSG_USER_ADDED 0x000c
240 #define MSG_EMAIL 0x000e
241 #define MSG_CONTACTS 0x0013
243 #define STATUS_ONLINE 0x00000000
244 #define STATUS_AWAY 0x00000001
245 #define STATUS_DND 0x00000013
246 #define STATUS_INVISIBLE 0x00000100
247 #define STATUS_OCCUPIED 0x00000010
248 #define STATUS_NA 0x00000004
249 #define STATUS_CHAT 0x00000020
251 /* Offsets for all packets measured from the start of the payload; i.e.
252 * with the ICQ header removed
254 #define CMD_ACK 0x000a
255 #define CMD_ACK_RANDOM 0x0000
257 #define CMD_SEND_MSG 0x010E
258 #define CMD_SEND_MSG_RECV_UIN 0x0000
259 #define CMD_SEND_MSG_MSG_TYPE 0x0004
260 #define CMD_SEND_MSG_MSG_LEN 0x0006
261 #define CMD_SEND_MSG_MSG_TEXT 0x0008
262 /* The rest of the packet should be a null-term string */
264 #define CMD_LOGIN 0x03E8
265 #define CMD_LOGIN_TIME 0x0000
266 #define CMD_LOGIN_PORT 0x0004
267 #define CMD_LOGIN_PASSLEN 0x0008
268 #define CMD_LOGIN_PASSWD 0x000A
269 /* The password is variable length; so when we've decoded the passwd,
270 * the structure starts counting at 0 again.
272 #define CMD_LOGIN_IP 0x0004
273 #define CMD_LOGIN_STATUS 0x0009
275 #define CMD_CONTACT_LIST 0x0406
276 #define CMD_CONTACT_LIST_NUM 0x0000
278 #define CMD_USER_META 0x064a
280 #define CMD_REG_NEW_USER 0x03fc
282 #define CMD_ACK_MESSAGES 0x0442
283 #define CMD_ACK_MESSAGES_RANDOM 0x0000
285 #define CMD_KEEP_ALIVE 0x042e
286 #define CMD_KEEP_ALIVE_RANDOM 0x0000
288 #define CMD_SEND_TEXT_CODE 0x0438
289 #define CMD_SEND_TEXT_CODE_LEN 0x0000
290 #define CMD_SEND_TEXT_CODE_TEXT 0x0002
292 #define CMD_MSG_TO_NEW_USER 0x0456
294 #define CMD_QUERY_SERVERS 0x04ba
296 #define CMD_QUERY_ADDONS 0x04c4
298 #define CMD_STATUS_CHANGE 0x04d8
299 #define CMD_STATUS_CHANGE_STATUS 0x0000
301 #define CMD_ADD_TO_LIST 0x053c
302 #define CMD_ADD_TO_LIST_UIN 0x0000
304 #define CMD_RAND_SEARCH 0x056e
305 #define CMD_RAND_SEARCH_GROUP 0x0000
307 #define CMD_META_USER 0x064a
309 cmdcode msgTypeCode[] = {
310 { "MSG_TEXT", MSG_TEXT },
311 { "MSG_URL", MSG_URL },
312 { "MSG_AUTH_REQ", MSG_AUTH_REQ },
313 { "MSG_AUTH", MSG_AUTH },
314 { "MSG_USER_ADDED", MSG_USER_ADDED},
315 { "MSG_EMAIL", MSG_EMAIL},
316 { "MSG_CONTACTS", MSG_CONTACTS},
320 cmdcode statusCode[] = {
321 { "ONLINE", STATUS_ONLINE },
322 { "AWAY", STATUS_AWAY },
323 { "DND", STATUS_DND },
324 { "INVISIBLE", STATUS_INVISIBLE },
325 { "OCCUPIED", STATUS_OCCUPIED },
327 { "Free for Chat", STATUS_CHAT },
331 cmdcode clientCmdCode[] = {
332 { "CMD_ACK", CMD_ACK },
333 { "CMD_SEND_MESSAGE", CMD_SEND_MSG },
334 { "CMD_LOGIN", CMD_LOGIN },
335 { "CMD_REG_NEW_USER", CMD_REG_NEW_USER },
336 { "CMD_CONTACT_LIST", 1030 },
337 { "CMD_SEARCH_UIN", 1050 },
338 { "CMD_SEARCH_USER", 1060 },
339 { "CMD_KEEP_ALIVE", 1070 },
340 { "CMD_SEND_TEXT_CODE", CMD_SEND_TEXT_CODE },
341 { "CMD_ACK_MESSAGES", CMD_ACK_MESSAGES },
342 { "CMD_LOGIN_1", 1100 },
343 { "CMD_MSG_TO_NEW_USER", CMD_MSG_TO_NEW_USER },
344 { "CMD_INFO_REQ", 1120 },
345 { "CMD_EXT_INFO_REQ", 1130 },
346 { "CMD_CHANGE_PW", 1180 },
347 { "CMD_NEW_USER_INFO", 1190 },
348 { "CMD_UPDATE_EXT_INFO", 1200 },
349 { "CMD_QUERY_SERVERS", CMD_QUERY_SERVERS },
350 { "CMD_QUERY_ADDONS", CMD_QUERY_ADDONS },
351 { "CMD_STATUS_CHANGE", CMD_STATUS_CHANGE },
352 { "CMD_NEW_USER_1", 1260 },
353 { "CMD_UPDATE_INFO", 1290 },
354 { "CMD_AUTH_UPDATE", 1300 },
355 { "CMD_KEEP_ALIVE2", 1310 },
356 { "CMD_LOGIN_2", 1320 },
357 { "CMD_ADD_TO_LIST", CMD_ADD_TO_LIST },
358 { "CMD_RAND_SET", 1380 },
359 { "CMD_RAND_SEARCH", CMD_RAND_SEARCH },
360 { "CMD_META_USER", CMD_META_USER },
361 { "CMD_INVIS_LIST", 1700 },
362 { "CMD_VIS_LIST", 1710 },
363 { "CMD_UPDATE_LIST", 1720 },
368 * All ICQv5 decryption code thanx to Sebastien Dault (daus01@gel.usherb.ca)
372 0x59, 0x60, 0x37, 0x6B, 0x65, 0x62, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x60, 0x57, 0x5B, 0x3D,
373 0x5E, 0x34, 0x6D, 0x36, 0x50, 0x3F, 0x6F, 0x67, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x47, 0x63, 0x39,
374 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x43, 0x69, 0x48, 0x33, 0x31, 0x64, 0x35, 0x5A, 0x4A, 0x42,
375 0x56, 0x40, 0x67, 0x53, 0x41, 0x07, 0x6C, 0x49, 0x58, 0x3B, 0x4D, 0x46, 0x68, 0x43, 0x69, 0x48,
376 0x33, 0x31, 0x44, 0x65, 0x62, 0x46, 0x48, 0x53, 0x41, 0x07, 0x6C, 0x69, 0x48, 0x33, 0x51, 0x54,
377 0x5D, 0x4E, 0x6C, 0x49, 0x38, 0x4B, 0x55, 0x4A, 0x62, 0x46, 0x48, 0x33, 0x51, 0x34, 0x6D, 0x36,
378 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x63, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64, 0x35, 0x5A,
379 0x6A, 0x52, 0x6E, 0x3C, 0x51, 0x34, 0x6D, 0x36, 0x50, 0x5F, 0x5F, 0x3F, 0x4F, 0x37, 0x4B, 0x35,
380 0x5A, 0x4A, 0x62, 0x66, 0x58, 0x3B, 0x4D, 0x66, 0x58, 0x5B, 0x5D, 0x4E, 0x6C, 0x49, 0x58, 0x3B,
381 0x4D, 0x66, 0x58, 0x3B, 0x4D, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64,
382 0x55, 0x6A, 0x32, 0x3E, 0x44, 0x45, 0x52, 0x6E, 0x3C, 0x31, 0x64, 0x55, 0x6A, 0x52, 0x4E, 0x6C,
383 0x69, 0x48, 0x53, 0x61, 0x4C, 0x39, 0x30, 0x6F, 0x47, 0x63, 0x59, 0x60, 0x57, 0x5B, 0x3D, 0x3E,
384 0x64, 0x35, 0x3A, 0x3A, 0x5A, 0x6A, 0x52, 0x4E, 0x6C, 0x69, 0x48, 0x53, 0x61, 0x6C, 0x49, 0x58,
385 0x3B, 0x4D, 0x46, 0x68, 0x63, 0x39, 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x67, 0x53, 0x41, 0x25, 0x41,
386 0x3C, 0x51, 0x54, 0x3D, 0x5E, 0x54, 0x5D, 0x4E, 0x4C, 0x39, 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F,
387 0x47, 0x43, 0x69, 0x48, 0x33, 0x51, 0x54, 0x5D, 0x6E, 0x3C, 0x31, 0x64, 0x35, 0x5A, 0x00, 0x00 };
390 findcmd(cmdcode* c, int num)
394 while (p->descr != NULL) {
395 if (p->code == num) {
400 snprintf(buf, sizeof(buf), "(%x)", num);
407 return findcmd(msgTypeCode, num);
413 return findcmd(serverMetaSubCmdCode, num);
417 findClientCmd(int num)
419 return findcmd(clientCmdCode, num);
423 findServerCmd(int num)
425 return findcmd(serverCmdCode, num);
431 return findcmd(statusCode, num);
435 get_v5key(tvbuff_t *tvb, int len)
437 guint32 a1, a2, a3, a4, a5;
438 guint32 code, check, key;
440 code = tvb_get_letohl(tvb, ICQ5_CL_CHECKCODE);
442 a1 = code & 0x0001f000;
443 a2 = code & 0x07c007c0;
444 a3 = code & 0x003e0001;
445 a4 = code & 0xf8000000;
446 a5 = code & 0x0000083e;
454 check = a5 + a1 + a2 + a3 + a4;
455 key = len * 0x68656C6C;
461 decrypt_v5(u_char *bfr, guint32 size,guint32 key)
465 for (i=ICQ5_CL_SESSIONID; i < size+3; i+=4 ) {
466 k = key+table_v5[i&0xff];
468 bfr[i] ^= (u_char)(k & 0xff);
469 bfr[i+1] ^= (u_char)((k & 0xff00)>>8);
472 bfr[i+2] ^= (u_char)((k & 0xff0000)>>16);
473 bfr[i+3] ^= (u_char)((k & 0xff000000)>>24);
479 dissect_icqv4(tvbuff_t *tvb,
483 /* Not really implemented yet */
484 if (check_col(pinfo->fd, COL_PROTOCOL)) {
485 col_set_str(pinfo->fd, COL_PROTOCOL, "ICQv4 (UDP)");
487 if (check_col(pinfo->fd, COL_INFO)) {
488 col_set_str(pinfo->fd, COL_INFO, "ICQ Version 4 protocol");
493 dissect_icqv3(tvbuff_t *tvb,
497 /* Not really implemented yet */
498 if (check_col(pinfo->fd, COL_PROTOCOL)) {
499 col_set_str(pinfo->fd, COL_PROTOCOL, "ICQv3 (UDP)");
501 if (check_col(pinfo->fd, COL_INFO)) {
502 col_set_str(pinfo->fd, COL_INFO, "ICQ Version 3 protocol");
507 dissect_icqv2(tvbuff_t *tvb,
511 /* Not really implemented yet */
512 if (check_col(pinfo->fd, COL_PROTOCOL)) {
513 col_set_str(pinfo->fd, COL_PROTOCOL, "ICQv2 (UDP)");
515 if (check_col(pinfo->fd, COL_INFO)) {
516 col_set_str(pinfo->fd, COL_INFO, "ICQ Version 2 protocol");
521 * The packet has, at offset "offset" a (len, string) pair.
522 * Display the length and string in the tree.
524 * If anything is wrong, return -1, since -1 is not a valid string
525 * length. Else, return the number of chars processed.
528 proto_add_icq_attr(proto_tree* tree, /* The tree to add to */
529 tvbuff_t *tvb, /* Tvbuff with packet */
530 const int offset, /* Offset from the start of packet of field */
531 char* descr) /* The description to use in the tree */
535 len = tvb_get_letohs(tvb, offset);
536 if (len > tvb_reported_length_remaining(tvb, offset))
537 return -1; /* length goes past end of packet */
538 proto_tree_add_text(tree, tvb,
540 sizeof(guint16) + len,
541 "%s[%u]: %.*s", descr, len, len,
542 tvb_get_ptr(tvb, offset + sizeof(guint16), len));
543 return len + sizeof(guint16);
547 icqv5_decode_msgType(proto_tree* tree,
552 proto_item* ti = NULL;
553 proto_tree* subtree = NULL;
557 int sz; /* Size of the current element */
559 static char* url_field_descr[] = {
563 #define N_URL_FIELDS (sizeof url_field_descr / sizeof url_field_descr[0])
564 static char* email_field_descr[] = {
572 #define N_EMAIL_FIELDS (sizeof email_field_descr / sizeof email_field_descr[0])
573 static char* auth_req_field_descr[] = {
581 #define N_AUTH_REQ_FIELDS (sizeof auth_req_field_descr / sizeof auth_req_field_descr[0])
582 static char* user_added_field_descr[] = {
588 #define N_USER_ADDED_FIELDS (sizeof user_added_field_descr / sizeof user_added_field_descr[0])
590 msgType = tvb_get_letohs(tvb, offset);
591 ti = proto_tree_add_text(tree, tvb,
594 "Message: Type = %u (%s)", msgType, findMsgType(msgType));
595 /* Create a new subtree */
596 subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
598 proto_tree_add_text(subtree, tvb,
601 "Type: %u (%s)", msgType, findMsgType(msgType));
604 if (msgType != MSG_AUTH) {
606 * XXX - does a MSG_AUTH message really have 3 bytes of information
607 * rather than a length field?
609 proto_tree_add_text(subtree, tvb,
613 tvb_get_letohs(tvb, offset));
619 case 0xffff: /* Field unknown */
622 fprintf(stderr, "Unknown msgType: %u (%04x)\n", msgType, msgType);
625 proto_tree_add_text(subtree, tvb,
629 tvb_get_ptr(tvb, offset, left));
632 for (n = 0; n < N_URL_FIELDS; n++) {
633 if (n != N_URL_FIELDS - 1) {
634 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
635 sz = sep_offset - offset + 1;
639 proto_tree_add_text(subtree, tvb,
645 tvb_get_ptr(tvb, offset, sz));
647 proto_tree_add_text(subtree, tvb,
650 "%s: %s", url_field_descr[n], "(empty)");
657 for (n = 0; n < N_EMAIL_FIELDS; n++) {
658 if (n != N_EMAIL_FIELDS - 1) {
659 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
660 sz = sep_offset - offset + 1;
664 proto_tree_add_text(subtree, tvb,
668 email_field_descr[n],
670 tvb_get_ptr(tvb, offset, sz));
672 proto_tree_add_text(subtree, tvb,
675 "%s: %s", email_field_descr[n], "(empty)");
684 /* Three bytes, first is a char signifying success */
685 unsigned char auth_suc;
687 auth_suc = tvb_get_guint8(tvb, offset);
688 proto_tree_add_text(subtree, tvb,
691 "Authorization: (%u) %s",auth_suc,
692 (auth_suc==0)?"Denied":"Allowed");
694 proto_tree_add_text(subtree, tvb,
698 tvb_get_letohs(tvb, offset));
702 for (n = 0; n < N_AUTH_REQ_FIELDS; n++) {
703 if (n != N_AUTH_REQ_FIELDS - 1) {
704 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
705 sz = sep_offset - offset + 1;
709 proto_tree_add_text(subtree, tvb,
713 auth_req_field_descr[n],
715 tvb_get_ptr(tvb, offset, sz));
717 proto_tree_add_text(subtree, tvb,
720 "%s: %s", auth_req_field_descr[n], "(empty)");
727 for (n = 0; n < N_USER_ADDED_FIELDS; n++) {
728 if (n != N_USER_ADDED_FIELDS - 1) {
729 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
730 sz = sep_offset - offset + 1;
734 proto_tree_add_text(subtree, tvb,
738 user_added_field_descr[n],
740 tvb_get_ptr(tvb, offset, sz));
742 proto_tree_add_text(subtree, tvb,
745 "%s: %s", user_added_field_descr[n], "(empty)");
753 gint sep_offset_prev;
754 int sz = 0; /* Size of the current element */
755 int n = 0; /* The nth element */
756 gboolean last = FALSE;
759 sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
760 if (sep_offset != -1)
761 sz = sep_offset - offset + 1;
767 /* The first element is the number of Nick/UIN pairs follow */
768 proto_tree_add_text(subtree, tvb,
771 "Number of pairs: %.*s",
773 tvb_get_ptr(tvb, offset, sz));
779 sep_offset_prev = sep_offset;
780 sep_offset = tvb_find_guint8(tvb, sep_offset_prev, left,
782 if (sep_offset != -1)
783 sz = sep_offset - offset + 1;
788 proto_tree_add_text(subtree, tvb,
793 tvb_get_ptr(tvb, offset, svsz),
795 tvb_get_ptr(tvb, sep_offset_prev + 1, sz));
800 offset = sep_offset + 1;
807 /*********************************
811 *********************************/
813 icqv5_cmd_ack(proto_tree* tree,/* Tree to put the data in */
814 tvbuff_t *tvb, /* Tvbuff with decrypted packet data */
815 int offset) /* Offset from the start of the packet to the content */
821 ti = proto_tree_add_uint_format(tree,
828 subtree = proto_item_add_subtree(ti, ett_icq_body);
829 proto_tree_add_text(subtree, tvb,
830 offset + CMD_ACK_RANDOM,
833 tvb_get_letohl(tvb, offset + CMD_ACK_RANDOM));
838 icqv5_cmd_rand_search(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 */
841 int size) /* Number of chars left to do */
847 static const char* groups[] = {
862 ti = proto_tree_add_uint_format(tree,
869 subtree = proto_item_add_subtree(ti, ett_icq_body);
870 group = tvb_get_letohs(tvb, offset + CMD_RAND_SEARCH_GROUP);
871 if (group>0 && (group<=sizeof(groups)/sizeof(const char*)))
872 proto_tree_add_text(subtree, tvb,
873 offset + CMD_RAND_SEARCH_GROUP,
875 "Group: (%u) %s", group, groups[group-1]);
877 proto_tree_add_text(subtree, tvb,
878 offset + CMD_RAND_SEARCH_GROUP,
880 "Group: (%u)", group);
885 icqv5_cmd_ack_messages(proto_tree* tree, /* Tree to put the data in */
886 tvbuff_t *tvb, /* Decrypted packet content */
887 int offset) /* Offset from the start of the packet to the content */
893 ti = proto_tree_add_uint_format(tree,
900 subtree = proto_item_add_subtree(ti, ett_icq_body);
901 proto_tree_add_text(subtree, tvb,
902 offset + CMD_ACK_MESSAGES_RANDOM,
905 tvb_get_letohl(tvb, offset + CMD_ACK_MESSAGES_RANDOM));
910 icqv5_cmd_keep_alive(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 */
919 ti = proto_tree_add_uint_format(tree,
926 subtree = proto_item_add_subtree(ti, ett_icq_body);
927 random = tvb_get_letohl(tvb, offset + CMD_KEEP_ALIVE_RANDOM);
928 proto_tree_add_text(subtree, tvb,
929 offset + CMD_KEEP_ALIVE_RANDOM,
931 "Random: 0x%08x", random);
936 icqv5_cmd_send_text_code(proto_tree* tree, /* Tree to put the data in */
937 tvbuff_t *tvb, /* Decrypted packet content */
938 int offset, /* Offset from the start of the packet to the content */
939 int size) /* Number of chars left to do */
941 proto_tree* subtree = NULL;
942 proto_item* ti = NULL;
947 ti = proto_tree_add_uint_format(tree,
956 len = tvb_get_letohs(tvb, offset+CMD_SEND_TEXT_CODE_LEN);
958 subtree = proto_item_add_subtree(ti, ett_icq_body);
959 proto_tree_add_text(subtree, tvb,
960 offset + CMD_SEND_TEXT_CODE_LEN,
967 proto_tree_add_text(subtree, tvb,
968 offset + CMD_SEND_TEXT_CODE_TEXT,
972 tvb_get_ptr(tvb, offset + CMD_SEND_TEXT_CODE_TEXT,
977 x1 = tvb_get_letohs(tvb, offset + CMD_SEND_TEXT_CODE_TEXT + len);
979 proto_tree_add_text(subtree, tvb,
980 offset + CMD_SEND_TEXT_CODE_TEXT + len,
987 icqv5_cmd_add_to_list(proto_tree* tree, /* Tree to put the data in */
988 tvbuff_t *tvb, /* Decrypted packet content */
989 int offset) /* Offset from the start of the packet to the content */
996 ti = proto_tree_add_uint_format(tree,
1003 subtree = proto_item_add_subtree(ti, ett_icq_body);
1004 uin = tvb_get_letohl(tvb, offset + CMD_ADD_TO_LIST);
1005 proto_tree_add_text(subtree, tvb,
1006 offset + CMD_ADD_TO_LIST_UIN,
1013 icqv5_cmd_status_change(proto_tree* tree, /* Tree to put the data in */
1014 tvbuff_t *tvb, /* Decrypted packet content */
1015 int offset) /* Offset from the start of the packet to the content */
1018 proto_tree* subtree;
1022 ti = proto_tree_add_uint_format(tree,
1029 subtree = proto_item_add_subtree(ti, ett_icq_body);
1030 status = tvb_get_letohl(tvb, offset + CMD_STATUS_CHANGE_STATUS);
1031 proto_tree_add_text(subtree, tvb,
1032 offset + CMD_STATUS_CHANGE_STATUS,
1034 "Status: %08x (%s)", status, findStatus(status));
1039 icqv5_cmd_send_msg(proto_tree* tree,
1045 proto_tree* subtree;
1047 int left = size; /* left chars to do */
1050 ti = proto_tree_add_uint_format(tree,
1057 subtree = proto_item_add_subtree(ti, ett_icq_body);
1058 proto_tree_add_text(subtree, tvb,
1059 offset + CMD_SEND_MSG_RECV_UIN,
1062 tvb_get_letohl(tvb, offset + CMD_SEND_MSG_RECV_UIN));
1065 icqv5_decode_msgType(subtree,
1067 offset + CMD_SEND_MSG_MSG_TYPE,
1073 icqv5_cmd_login(proto_tree* tree,
1079 proto_tree* subtree;
1084 const u_char *ipAddrp;
1088 ti = proto_tree_add_uint_format(tree,
1095 subtree = proto_item_add_subtree(ti, ett_icq_body);
1096 theTime = tvb_get_letohl(tvb, offset + CMD_LOGIN_TIME);
1097 aTime = ctime(&theTime);
1098 aTime[strlen(aTime)-1] = '\0';
1099 proto_tree_add_text(subtree, tvb,
1100 offset + CMD_LOGIN_TIME,
1102 "Time: %ld = %s", (long)theTime, aTime);
1103 port = tvb_get_letohl(tvb, offset + CMD_LOGIN_PORT);
1104 proto_tree_add_text(subtree, tvb,
1105 offset + CMD_LOGIN_PORT,
1108 passwdLen = tvb_get_letohs(tvb, offset + CMD_LOGIN_PASSLEN);
1109 proto_tree_add_text(subtree, tvb,
1110 offset + CMD_LOGIN_PASSLEN,
1114 tvb_get_ptr(tvb, offset + CMD_LOGIN_PASSWD,
1116 ipAddrp = tvb_get_ptr(tvb,
1117 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP,
1119 proto_tree_add_text(subtree, tvb,
1120 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP,
1122 "IP: %s", ip_to_str(ipAddrp));
1123 status = tvb_get_letohs(tvb,
1124 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS);
1125 proto_tree_add_text(subtree, tvb,
1126 offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS,
1128 "Status: %s", findStatus(status));
1133 icqv5_cmd_contact_list(proto_tree* tree,
1138 proto_tree* subtree;
1145 ti = proto_tree_add_uint_format(tree,
1152 subtree = proto_item_add_subtree(ti, ett_icq_body);
1153 num = tvb_get_guint8(tvb, offset + CMD_CONTACT_LIST_NUM);
1154 proto_tree_add_text(subtree, tvb,
1155 offset + CMD_CONTACT_LIST,
1157 "Number of uins: %u", num);
1159 * A sequence of num times UIN follows
1161 offset += (CMD_CONTACT_LIST_NUM + 1);
1162 for (i = 0; i < num; i++) {
1163 uin = tvb_get_letohl(tvb, offset);
1164 proto_tree_add_text(subtree, tvb,
1167 "UIN[%d]: %u", i ,uin);
1174 icqv5_cmd_no_params(proto_tree* tree, /* Tree to put the data in */
1175 tvbuff_t *tvb, /* Decrypted packet content */
1176 int offset, /* Offset from the start of the packet to the content */
1179 proto_tree* subtree;
1183 ti = proto_tree_add_uint_format(tree,
1190 subtree = proto_item_add_subtree(ti, ett_icq_body);
1191 proto_tree_add_text(subtree, tvb,
1198 /**********************
1202 **********************
1205 icqv5_srv_no_params(proto_tree* tree, /* Tree to put the data in */
1206 tvbuff_t *tvb, /* Packet content */
1207 int offset, /* Offset from the start of the packet to the content */
1208 int size, /* Number of chars left to do */
1211 proto_tree* subtree;
1215 ti = proto_tree_add_uint_format(tree,
1222 subtree = proto_item_add_subtree(ti, ett_icq_body);
1223 proto_tree_add_text(subtree, tvb,
1231 icqv5_srv_login_reply(proto_tree* tree,/* Tree to put the data in */
1232 tvbuff_t *tvb, /* Tvbuff with packet */
1233 int offset, /* Offset from the start of the packet to the content */
1234 int size) /* Number of chars left to do */
1236 proto_tree* subtree;
1238 const u_char *ipAddrp;
1241 ti = proto_tree_add_uint_format(tree,
1245 SRV_LOGIN_REPLY_IP + 8,
1248 subtree = proto_item_add_subtree(ti, ett_icq_body);
1249 ipAddrp = tvb_get_ptr(tvb, offset + SRV_LOGIN_REPLY_IP, 4);
1250 proto_tree_add_text(subtree, tvb,
1251 offset + SRV_LOGIN_REPLY_IP,
1253 "IP: %s", ip_to_str(ipAddrp));
1258 icqv5_srv_user_online(proto_tree* tree,/* Tree to put the data in */
1259 tvbuff_t *tvb, /* Tvbuff with packet */
1260 int offset, /* Offset from the start of the packet to the content */
1261 int size) /* Number of chars left to do */
1263 proto_tree* subtree;
1265 const u_char *ipAddrp;
1266 const u_char *realipAddrp;
1270 ti = proto_tree_add_uint_format(tree,
1274 SRV_LOGIN_REPLY_IP + 8,
1277 subtree = proto_item_add_subtree(ti, ett_icq_body);
1278 proto_tree_add_text(subtree, tvb,
1279 offset + SRV_USER_ONL_UIN,
1282 tvb_get_letohl(tvb, offset + SRV_USER_ONL_UIN));
1283 ipAddrp = tvb_get_ptr(tvb, offset + SRV_USER_ONL_IP, 4);
1284 proto_tree_add_text(subtree, tvb,
1285 offset + SRV_USER_ONL_IP,
1287 "IP: %s", ip_to_str(ipAddrp));
1288 proto_tree_add_text(subtree, tvb,
1289 offset + SRV_USER_ONL_PORT,
1292 tvb_get_letohl(tvb, offset + SRV_USER_ONL_PORT));
1293 realipAddrp = tvb_get_ptr(tvb, offset + SRV_USER_ONL_REALIP, 4);
1294 proto_tree_add_text(subtree, tvb,
1295 offset + SRV_USER_ONL_REALIP,
1297 "RealIP: %s", ip_to_str(realipAddrp));
1298 status = tvb_get_letohs(tvb, offset + SRV_USER_ONL_STATUS);
1299 proto_tree_add_text(subtree, tvb,
1300 offset + SRV_USER_ONL_STATUS,
1302 "Status: %s", findStatus(status));
1304 * Kojak: Hypothesis is that this field might be an encoding for the
1305 * version used by the UIN that changed. To test this, I included
1306 * this line to the code.
1308 proto_tree_add_text(subtree, tvb,
1309 offset + SRV_USER_ONL_X2,
1312 tvb_get_letohl(tvb, offset + SRV_USER_ONL_X2));
1317 icqv5_srv_user_offline(proto_tree* tree,/* Tree to put the data in */
1318 tvbuff_t *tvb, /* Tvbuff with packet */
1319 int offset, /* Offset from the start of the packet to the content */
1320 int size) /* Number of chars left to do */
1322 proto_tree* subtree;
1326 ti = proto_tree_add_uint_format(tree,
1330 SRV_USER_OFFLINE_UIN + 4,
1333 subtree = proto_item_add_subtree(ti, ett_icq_body);
1334 proto_tree_add_text(subtree, tvb,
1335 offset + SRV_USER_OFFLINE_UIN,
1338 tvb_get_letohl(tvb, offset + SRV_USER_OFFLINE));
1343 icqv5_srv_multi(proto_tree* tree, /* Tree to put the data in */
1344 tvbuff_t *tvb, /* Packet content */
1345 int offset, /* Offset from the start of the packet to the content */
1346 int size, /* Number of chars left to do */
1349 proto_tree* subtree;
1351 unsigned char num = -1;
1356 ti = proto_tree_add_uint_format(tree,
1363 subtree = proto_item_add_subtree(ti, ett_icq_body);
1364 num = tvb_get_guint8(tvb, offset + SRV_MULTI_NUM);
1365 proto_tree_add_text(subtree, tvb,
1366 offset + SRV_MULTI_NUM,
1368 "Number of pkts: %u", num);
1370 * A sequence of num times ( pktsize, packetData) follows
1372 offset += (SRV_MULTI_NUM + 1);
1374 for (i = 0; (i<num) && (left>0);i++) {
1376 pktSz = tvb_get_letohs(tvb, offset);
1380 dissect_icqv5Server(tvb, offset, pinfo, subtree, pktSz);
1390 icqv5_srv_meta_user(proto_tree* tree, /* Tree to put the data in */
1391 tvbuff_t *tvb, /* Tvbuff with packet */
1392 int offset, /* Offset from the start of the packet to the content */
1393 int size) /* Number of chars left to do */
1396 proto_tree* subtree = NULL;
1398 proto_tree* sstree = NULL;
1399 proto_item* ti = NULL;
1402 unsigned char result;
1406 ti = proto_tree_add_uint_format(tree,
1413 subtree = proto_item_add_subtree(ti, ett_icq_body);
1414 subcmd = tvb_get_letohs(tvb, offset + SRV_META_USER_SUBCMD);
1415 ti = proto_tree_add_text(subtree, tvb,
1416 offset + SRV_META_USER_SUBCMD,
1418 "%s", findSubCmd(subcmd));
1419 result = tvb_get_guint8(tvb, offset + SRV_META_USER_RESULT);
1420 proto_tree_add_text(subtree, tvb,
1421 offset + SRV_META_USER_RESULT,
1423 "%s", (result==0x0a)?"Success":"Failure");
1424 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1426 subcmd = tvb_get_letohs(tvb, offset + SRV_META_USER_SUBCMD);
1427 ti = proto_tree_add_text(tree, tvb,
1428 offset + SRV_META_USER_SUBCMD,
1430 "%s", findSubCmd(subcmd));
1431 sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
1432 result = tvb_get_guint8(tvb, offset + SRV_META_USER_RESULT);
1433 proto_tree_add_text(sstree, tvb,
1434 offset + SRV_META_USER_RESULT,
1436 "%s", (result==0x0a)?"Success":"Failure");
1439 /* Skip the META_USER header */
1444 case META_EX_USER_FOUND:
1446 /* This is almost the same as META_USER_FOUND,
1447 * however, there's an extra length field
1449 guint16 pktLen = -1;
1451 /* Read the length field */
1452 pktLen = tvb_get_letohs(tvb, offset);
1453 proto_tree_add_text(sstree, tvb,
1456 "Length: %u", pktLen);
1458 offset += sizeof(guint16); left -= sizeof(guint16);
1460 case META_USER_FOUND:
1462 /* The goto mentioned in this block should be local to this
1463 * block if C'd allow it.
1465 * They are used to "implement" a poorman's exception handling
1479 proto_tree_add_text(sstree, tvb,
1483 tvb_get_letohl(tvb, offset));
1484 offset+=sizeof(guint32);left-=sizeof(guint32);
1486 for ( ; *d!=NULL; d++) {
1487 len = proto_add_icq_attr(sstree,
1493 offset += len; left -= len;
1495 /* Get the authorize setting */
1496 auth = tvb_get_guint8(tvb, offset);
1497 proto_tree_add_text(sstree, tvb,
1500 "authorization: %s", (auth==0x01)?"Neccessary":"Who needs it");
1503 proto_tree_add_text(sstree, tvb,
1507 tvb_get_letohs(tvb, offset));
1508 offset+=sizeof(guint16);left-=sizeof(guint16);
1510 proto_tree_add_text(sstree, tvb,
1514 tvb_get_letohl(tvb, offset));
1515 offset+=sizeof(guint32);left-=sizeof(guint32);
1522 /* Get the about information */
1523 len = tvb_get_letohs(tvb, offset);
1524 offset+=sizeof(guint16);left-=sizeof(guint16);
1525 proto_tree_add_text(sstree, tvb,
1526 offset - sizeof(guint16),
1527 sizeof(guint16)+len,
1528 "About(%d): %.*s", len,
1529 len, tvb_get_ptr(tvb, offset, len));
1530 offset+=len;left-=len;
1533 case META_USER_INFO:
1535 /* The goto mentioned in this block should be local to this
1536 * block if C'd allow it.
1538 * They are used to "implement" a poorman's exception handling
1540 static const char* descr[] = {
1555 const char** d = descr;
1557 unsigned char user_timezone = -1;
1558 unsigned char auth = -1;
1562 uin = tvb_get_letohl(tvb, offset);
1563 proto_tree_add_text(sstree, tvb,
1567 offset+=sizeof(guint32);left-=sizeof(guint32);
1571 * Get every field from the description
1573 while ((*d)!=NULL) {
1574 len = tvb_get_letohs(tvb, offset);
1575 offset+=sizeof(guint16);left-=sizeof(guint16);
1577 proto_tree_add_text(sstree, tvb,
1578 offset - sizeof(guint16),
1579 sizeof(guint16)+len,
1580 "%s(%d): %.*s",*d, len,
1582 tvb_get_ptr(tvb, offset, len - 1));
1583 offset+=len;left-=len;
1587 /* Get country code */
1588 country = tvb_get_letohs(tvb, offset);
1589 proto_tree_add_text(sstree, tvb,
1592 "Countrycode: %u", country);
1593 offset+=sizeof(guint16); left-=sizeof(guint16);
1594 /* Get the timezone setting */
1595 user_timezone = tvb_get_guint8(tvb, offset);
1596 proto_tree_add_text(sstree, tvb,
1598 sizeof(unsigned char),
1599 "Timezone: %u", user_timezone);
1601 /* Get the authorize setting */
1602 auth = tvb_get_guint8(tvb, offset);
1603 proto_tree_add_text(sstree, tvb,
1605 sizeof(unsigned char),
1606 "Authorization: (%u) %s",
1607 auth, (auth==0)?"No":"Yes");
1609 /* Get the webaware setting */
1610 auth = tvb_get_guint8(tvb, offset);
1611 proto_tree_add_text(sstree, tvb,
1613 sizeof(unsigned char),
1614 "Webaware: (%u) %s",
1615 auth, (auth==0)?"No":"Yes");
1617 /* Get the authorize setting */
1618 auth = tvb_get_guint8(tvb, offset);
1619 proto_tree_add_text(sstree, tvb,
1621 sizeof(unsigned char),
1623 auth, (auth==0)?"No":"Yes");
1628 /* This information is already printed in the tree */
1629 fprintf(stderr, "Meta subcmd: %04x\n", subcmd);
1636 icqv5_srv_recv_message(proto_tree* tree, /* Tree to put the data in */
1637 tvbuff_t* tvb, /* Packet content */
1638 int offset, /* Offset from the start of the packet to the content */
1639 int size) /* Number of chars left to do */
1641 proto_tree* subtree = NULL;
1642 proto_item* ti = NULL;
1646 unsigned char month = -1;
1647 unsigned char day = -1;
1648 unsigned char hour = -1;
1649 unsigned char minute = -1;
1652 ti = proto_tree_add_uint_format(tree,
1659 subtree = proto_item_add_subtree(ti, ett_icq_body);
1660 uin = tvb_get_letohl(tvb, offset + SRV_RECV_MSG_UIN);
1661 proto_tree_add_uint_format(subtree,
1664 offset + SRV_RECV_MSG_UIN,
1668 year = tvb_get_letohs(tvb, offset + SRV_RECV_MSG_YEAR);
1669 month = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_MONTH);
1670 day = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_DAY);
1671 hour = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_HOUR);
1672 minute = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_MINUTE);
1674 proto_tree_add_text(subtree, tvb,
1675 offset + SRV_RECV_MSG_YEAR,
1676 sizeof(guint16) + 4*sizeof(unsigned char),
1677 "Time: %u-%u-%u %02u:%02u",
1678 day, month, year, hour, minute);
1679 icqv5_decode_msgType(subtree,
1681 offset + SRV_RECV_MSG_MSG_TYPE,
1687 icqv5_srv_rand_user(proto_tree* tree, /* Tree to put the data in */
1688 tvbuff_t *tvb, /* Tvbuff with packet */
1689 int offset) /* Offset from the start of the packet to the content */
1691 proto_tree* subtree = NULL;
1692 proto_item* ti = NULL;
1694 const unsigned char* IP = NULL;
1696 const unsigned char* realIP = NULL;
1697 unsigned char commClass = -1;
1702 ti = proto_tree_add_uint_format(tree,
1706 SRV_RAND_USER_TCP_VER + 2,
1709 subtree = proto_item_add_subtree(ti, ett_icq_body);
1711 uin = tvb_get_letohl(tvb, offset + SRV_RAND_USER_UIN);
1712 proto_tree_add_text(subtree, tvb,
1713 offset + SRV_RAND_USER_UIN,
1717 IP = tvb_get_ptr(tvb, offset + SRV_RAND_USER_IP, 4);
1718 proto_tree_add_text(subtree, tvb,
1719 offset + SRV_RAND_USER_IP,
1723 /* guint32 portNum */
1724 port = tvb_get_letohs(tvb, offset + SRV_RAND_USER_PORT);
1725 proto_tree_add_text(subtree, tvb,
1726 offset + SRV_RAND_USER_UIN,
1729 /* guint32 realIP */
1730 realIP = tvb_get_ptr(tvb, offset + SRV_RAND_USER_REAL_IP, 4);
1731 proto_tree_add_text(subtree, tvb,
1732 offset + SRV_RAND_USER_REAL_IP,
1734 "RealIP: %s", ip_to_str(realIP));
1735 /* guit16 Communication Class */
1736 commClass = tvb_get_guint8(tvb, offset + SRV_RAND_USER_CLASS);
1737 proto_tree_add_text(subtree, tvb,
1738 offset + SRV_RAND_USER_CLASS,
1739 sizeof(unsigned char),
1740 "Class: %s", (commClass!=4)?"User to User":"Through Server");
1741 /* guint32 status */
1742 status = tvb_get_letohs(tvb, offset + SRV_RAND_USER_STATUS);
1743 proto_tree_add_text(subtree, tvb,
1744 offset + SRV_RAND_USER_STATUS,
1746 "Status: (%u) %s", status, findStatus(status));
1747 /* guint16 tcpVersion */
1748 tcpVer = tvb_get_letohs(tvb, offset + SRV_RAND_USER_TCP_VER);
1749 proto_tree_add_text(subtree, tvb,
1750 offset + SRV_RAND_USER_TCP_VER,
1752 "TCPVersion: %u", tcpVer);
1757 * Dissect all the v5 client traffic. This is encrypted, so be careful.
1760 dissect_icqv5Client(tvbuff_t *tvb,
1764 proto_tree *icq_tree = NULL;
1765 proto_tree *icq_header_tree = NULL;
1766 proto_item *ti = NULL;
1768 guint16 pktsize; /* The size of the ICQ content */
1771 static u_char *decr_pd = NULL; /* Decrypted content */
1772 static int decr_size = 0; /* Size of decrypted-content buffer */
1775 pktsize = tvb_length(tvb);
1777 if (decr_size == 0) {
1778 decr_size = sizeof(u_char) * 128;
1779 decr_pd = g_malloc(decr_size);
1782 while (decr_size < pktsize + 3) {
1784 decr_pd = g_realloc(decr_pd, decr_size);
1787 /* Get the encryption key */
1788 key = get_v5key(tvb, pktsize);
1790 /* Make a copy of the packet data, and decrypt it */
1791 tvb_memcpy(tvb, decr_pd, 0, pktsize);
1792 decrypt_v5(decr_pd, pktsize, key);
1794 /* Allocate a new tvbuff, referring to the decrypted data. */
1795 decr_tvb = tvb_new_real_data(decr_pd, pktsize, tvb_reported_length(tvb),
1798 /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
1799 were handed refers, so it'll get cleaned up when that tvbuff
1801 tvb_set_child_real_data_tvbuff(tvb, decr_tvb);
1803 /* Add the decrypted data to the data source list. */
1804 pinfo->fd->data_src = g_slist_append(pinfo->fd->data_src, decr_tvb);
1806 cmd = tvb_get_letohs(decr_tvb, ICQ5_CL_CMD);
1808 if (check_col(pinfo->fd, COL_INFO))
1809 col_add_fstr(pinfo->fd, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
1812 ti = proto_tree_add_protocol_format(tree,
1817 "ICQv5 %s (len %u)",
1820 icq_tree = proto_item_add_subtree(ti, ett_icq);
1821 ti = proto_tree_add_uint_format(icq_tree,
1828 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
1830 proto_tree_add_text(icq_header_tree, tvb,
1834 tvb_get_letohs(tvb, ICQ_VERSION));
1835 proto_tree_add_item(icq_header_tree,
1841 proto_tree_add_item(icq_header_tree,
1847 proto_tree_add_text(icq_header_tree, decr_tvb,
1850 "Command: %s (%u)", findClientCmd(cmd), cmd);
1851 proto_tree_add_text(icq_header_tree, decr_tvb,
1854 "Seq Number 1: 0x%04x",
1855 tvb_get_letohs(decr_tvb, ICQ5_CL_SEQNUM1));
1856 proto_tree_add_text(icq_header_tree, decr_tvb,
1859 "Seq Number 2: 0x%04x",
1860 tvb_get_letohs(decr_tvb, ICQ5_CL_SEQNUM2));
1861 proto_tree_add_uint_format(icq_header_tree,
1871 icqv5_cmd_ack(icq_tree,
1876 case CMD_MSG_TO_NEW_USER:
1877 icqv5_cmd_send_msg(icq_tree,
1880 pktsize - ICQ5_CL_HDRSIZE,
1883 case CMD_RAND_SEARCH:
1884 icqv5_cmd_rand_search(icq_tree,
1887 pktsize - ICQ5_CL_HDRSIZE);
1890 icqv5_cmd_login(icq_tree,
1893 pktsize - ICQ5_CL_HDRSIZE);
1895 case CMD_SEND_TEXT_CODE:
1896 icqv5_cmd_send_text_code(icq_tree,
1899 pktsize - ICQ5_CL_HDRSIZE);
1901 case CMD_STATUS_CHANGE:
1902 icqv5_cmd_status_change(icq_tree,
1906 case CMD_ACK_MESSAGES:
1907 icqv5_cmd_ack_messages(icq_tree,
1911 case CMD_KEEP_ALIVE:
1912 icqv5_cmd_keep_alive(icq_tree,
1916 case CMD_ADD_TO_LIST:
1917 icqv5_cmd_add_to_list(icq_tree,
1921 case CMD_CONTACT_LIST:
1922 icqv5_cmd_contact_list(icq_tree,
1925 pktsize - ICQ5_CL_HDRSIZE);
1928 case CMD_REG_NEW_USER:
1929 case CMD_QUERY_SERVERS:
1930 case CMD_QUERY_ADDONS:
1931 icqv5_cmd_no_params(icq_tree,
1937 proto_tree_add_uint_format(icq_tree,
1944 cmd, findClientCmd(cmd));
1945 fprintf(stderr,"Missing: %s\n", findClientCmd(cmd));
1952 dissect_icqv5Server(tvbuff_t *tvb,
1958 /* Server traffic is easy, not encrypted */
1959 proto_tree *icq_tree = NULL;
1960 proto_tree *icq_header_tree = NULL;
1961 proto_item *ti = NULL;
1962 int changeCol = (pktsize==(guint32)-1);
1966 cmd = tvb_get_letohs(tvb, offset + ICQ5_SRV_CMD);
1967 if (changeCol && check_col(pinfo->fd, COL_INFO))
1968 col_add_fstr(pinfo->fd, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
1971 pktsize = tvb_reported_length(tvb);
1974 ti = proto_tree_add_protocol_format(tree,
1979 "ICQv5 %s (len %u)",
1983 icq_tree = proto_item_add_subtree(ti, ett_icq);
1985 ti = proto_tree_add_uint_format(icq_tree,
1992 icq_header_tree = proto_item_add_subtree(ti, ett_icq_header);
1994 proto_tree_add_text(icq_header_tree, tvb,
1995 offset + ICQ_VERSION,
1998 tvb_get_letohs(tvb, ICQ_VERSION));
1999 proto_tree_add_item(icq_header_tree,
2002 offset + ICQ5_SRV_SESSIONID,
2005 proto_tree_add_text(icq_header_tree, tvb,
2006 offset + ICQ5_SRV_CMD,
2008 "Command: %s (%u)", findServerCmd(cmd), cmd);
2009 proto_tree_add_text(icq_header_tree, tvb,
2010 offset + ICQ5_SRV_SEQNUM1,
2012 "Seq Number 1: 0x%04x",
2013 tvb_get_letohs(tvb, offset + ICQ5_SRV_SEQNUM1));
2014 proto_tree_add_text(icq_header_tree, tvb,
2015 offset + ICQ5_SRV_SEQNUM2,
2017 "Seq Number 2: 0x%04x",
2018 tvb_get_letohs(tvb, offset + ICQ5_SRV_SEQNUM2));
2019 proto_tree_add_item(icq_header_tree,
2022 offset + ICQ5_SRV_UIN,
2025 proto_tree_add_item(icq_header_tree,
2028 offset + ICQ5_SRV_CHECKCODE,
2033 icqv5_srv_rand_user(icq_tree,
2035 offset + ICQ5_SRV_HDRSIZE);
2037 case SRV_SYS_DELIVERED_MESS:
2038 /* The message structures are all the same. Why not run
2039 * the same routine? */
2040 icqv5_cmd_send_msg(icq_tree,
2042 offset + ICQ5_SRV_HDRSIZE,
2043 pktsize - ICQ5_SRV_HDRSIZE,
2046 case SRV_USER_ONLINE:
2047 icqv5_srv_user_online(icq_tree,
2049 offset + ICQ5_SRV_HDRSIZE,
2050 pktsize - ICQ5_SRV_HDRSIZE);
2052 case SRV_USER_OFFLINE:
2053 icqv5_srv_user_offline(icq_tree,
2055 offset + ICQ5_SRV_HDRSIZE,
2056 pktsize - ICQ5_SRV_HDRSIZE);
2058 case SRV_LOGIN_REPLY:
2059 icqv5_srv_login_reply(icq_tree,
2061 offset + ICQ5_SRV_HDRSIZE,
2062 pktsize - ICQ5_SRV_HDRSIZE);
2065 icqv5_srv_meta_user(icq_tree,
2067 offset + ICQ5_SRV_HDRSIZE,
2068 pktsize - ICQ5_SRV_HDRSIZE);
2070 case SRV_RECV_MESSAGE:
2071 icqv5_srv_recv_message(icq_tree,
2073 offset + ICQ5_SRV_HDRSIZE,
2074 pktsize - ICQ5_SRV_HDRSIZE);
2077 icqv5_srv_multi(icq_tree,
2079 offset + ICQ5_SRV_HDRSIZE,
2080 pktsize - ICQ5_SRV_HDRSIZE,
2084 case SRV_SILENT_TOO_LONG:
2088 case SRV_UPDATE_SUCCESS:
2089 icqv5_srv_no_params(icq_tree,
2091 offset + ICQ5_SRV_HDRSIZE,
2092 pktsize - ICQ5_SRV_HDRSIZE,
2096 proto_tree_add_uint_format(icq_tree,
2103 cmd, findServerCmd(cmd));
2104 fprintf(stderr,"Missing: %s\n", findServerCmd(cmd));
2110 static void dissect_icqv5(tvbuff_t *tvb,
2116 if (check_col(pinfo->fd, COL_PROTOCOL))
2117 col_set_str(pinfo->fd, COL_PROTOCOL, "ICQv5 (UDP)");
2118 if (check_col(pinfo->fd, COL_INFO))
2119 col_set_str(pinfo->fd, COL_INFO, "ICQv5 packet");
2121 unknown = tvb_get_letohl(tvb, ICQ5_UNKNOWN);
2123 if (unknown == 0x0L) {
2124 dissect_icqv5Client(tvb, pinfo, tree);
2126 dissect_icqv5Server(tvb, 0, pinfo, tree, (guint32) -1);
2130 static void dissect_icq(tvbuff_t *tvb,
2136 if (check_col(pinfo->fd, COL_PROTOCOL)) {
2137 col_set_str(pinfo->fd, COL_PROTOCOL, "ICQ");
2139 if (check_col(pinfo->fd, COL_INFO)) {
2140 col_clear(pinfo->fd, COL_INFO);
2143 version = tvb_get_letohs(tvb, ICQ_VERSION);
2146 dissect_icqv5(tvb, pinfo, tree);
2149 dissect_icqv4(tvb, pinfo, tree);
2152 dissect_icqv3(tvb, pinfo, tree);
2155 dissect_icqv2(tvb, pinfo, tree);
2158 fprintf(stderr, "ICQ: Unknown version (%d)\n", version);
2163 /* registration with the filtering engine */
2165 proto_register_icq(void)
2167 static hf_register_info hf[] = {
2169 {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2171 {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, ""}},
2172 { &hf_icq_sessionid,
2173 {"Session ID", "icq.sessionid", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2175 {"Command", "icq.cmd", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
2176 { &hf_icq_checkcode,
2177 {"Checkcode", "icq.checkcode", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
2179 {"Decode", "icq.decode", FT_STRING, BASE_NONE, NULL, 0x0, ""}}
2181 static gint *ett[] = {
2186 &ett_icq_body_parts,
2189 proto_icq = proto_register_protocol("ICQ Protocol", "ICQ", "icq");
2191 proto_register_field_array(proto_icq, hf, array_length(hf));
2193 proto_register_subtree_array(ett, array_length(ett));
2197 proto_reg_handoff_icq(void)
2199 dissector_add("udp.port", UDP_PORT_ICQ, dissect_icq, proto_icq);