2 * Routines for ICQ packet disassembly
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
12 * This file: by Kojak <kojak@bigwig.net>
14 * Decoding code ripped, reference to the original author at the
15 * appropriate place with the code itself.
20 #include <epan/packet.h>
21 #include <epan/to_str.h>
22 #include <epan/expert.h>
24 #include <wsutil/array.h>
26 void proto_register_icq(void);
27 void proto_reg_handoff_icq(void);
29 static dissector_handle_t icq_handle
;
32 static int hf_icq_version
;
33 static int hf_icq_uin
;
34 static int hf_icq_client_cmd
;
35 static int hf_icq_server_cmd
;
36 static int hf_icq_sessionid
;
37 static int hf_icq_checkcode
;
38 static int hf_icq_type
;
39 static int hf_icq_msg_type
;
40 static int hf_icq_seqnum1
;
41 static int hf_icq_seqnum2
;
42 static int hf_icq_checkcode_key
;
43 static int hf_icq_group
;
44 static int hf_icq_ack_random
;
45 static int hf_icq_keep_alive_random
;
46 static int hf_icq_status
;
47 static int hf_icq_meta_user_subcmd
;
48 /* Generated from convert_proto_tree_add_text.pl */
49 static int hf_icq_rand_user_tcpversion
;
50 static int hf_icq_meta_user_x3
;
51 static int hf_icq_user_online_realip
;
52 static int hf_icq_rand_user_realip
;
53 static int hf_icq_meta_user_hideip
;
54 static int hf_icq_user_online_port
;
55 static int hf_icq_user_online_ip
;
56 static int hf_icq_num_uin_pairs
;
58 static int hf_icq_meta_user_timezone
;
59 static int hf_icq_user_online_version
;
60 static int hf_icq_receiver_uin
;
61 static int hf_icq_text_code
;
62 static int hf_icq_login_reply_ip
;
63 static int hf_icq_rand_user_ip
;
64 static int hf_icq_multi_num_packets
;
65 static int hf_icq_number_of_uins
;
66 static int hf_icq_meta_user_length
;
67 static int hf_icq_text_code_length
;
68 static int hf_icq_login_password
;
69 static int hf_icq_meta_user_x2
;
70 static int hf_icq_login_time
;
71 static int hf_icq_meta_user_countrycode
;
72 static int hf_icq_msg_length
;
73 static int hf_icq_meta_user_about
;
74 static int hf_icq_meta_user_webaware
;
75 static int hf_icq_rand_user_class
;
76 static int hf_icq_rand_user_port
;
77 static int hf_icq_meta_user_found_authorization
;
78 static int hf_icq_meta_user_info_authorization
;
79 static int hf_icq_no_parameters
;
80 static int hf_icq_login_port
;
81 static int hf_icq_meta_user_result
;
82 static int hf_icq_login_ip
;
83 static int hf_icq_msg_authorization
;
84 static int hf_icq_msg
;
85 static int hf_icq_nickname
;
86 static int hf_icq_first_name
;
87 static int hf_icq_last_name
;
88 static int hf_icq_email
;
89 static int hf_icq_nickname_uint_string
;
90 static int hf_icq_first_name_uint_string
;
91 static int hf_icq_last_name_uint_string
;
92 static int hf_icq_email_uint_string
;
93 static int hf_icq_primary_email
;
94 static int hf_icq_secondary_email
;
95 static int hf_icq_old_email
;
96 static int hf_icq_city
;
97 static int hf_icq_state
;
98 static int hf_icq_phone
;
99 static int hf_icq_fax
;
100 static int hf_icq_street
;
101 static int hf_icq_cellphone
;
102 static int hf_icq_zip
;
103 static int hf_icq_description
;
104 static int hf_icq_url
;
105 static int hf_icq_text
;
106 static int hf_icq_unknown
;
107 static int hf_icq_reason
;
108 static int hf_icq_msg_contact
;
109 static int hf_icq_recv_time
;
112 static int ett_icq_header
;
113 static int ett_icq_body
;
114 static int ett_icq_body_parts
;
116 static expert_field ei_icq_unknown_meta_subcmd
;
117 static expert_field ei_icq_unknown_command
;
119 /* This is not IANA registered */
120 #define UDP_PORT_ICQ 4000
122 #define ICQ5_SERVER 0
123 #define ICQ5_CLIENT 1
126 dissect_icqv5Server(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
127 proto_tree
*tree
, int pktsize
);
129 /* Offsets of fields in the ICQ headers */
130 /* Can be 0x0002 or 0x0005 */
131 #define ICQ_VERSION 0x00
132 /* Is either one (server) or four (client) bytes long */
133 /* Client header offsets */
134 #define ICQ5_UNKNOWN 0x02
135 #define ICQ5_CL_UIN 0x06
136 #define ICQ5_CL_SESSIONID 0x0a
137 #define ICQ5_CL_CMD 0x0e
138 #define ICQ5_CL_SEQNUM1 0x10
139 #define ICQ5_CL_SEQNUM2 0x12
140 #define ICQ5_CL_CHECKCODE 0x14
141 #define ICQ5_CL_PARAM 0x18
142 #define ICQ5_CL_HDRSIZE 0x18
144 /* Server header offsets */
145 #define ICQ5_SRV_SESSIONID 0x03
146 #define ICQ5_SRV_CMD 0x07
147 #define ICQ5_SRV_SEQNUM1 0x09
148 #define ICQ5_SRV_SEQNUM2 0x0b
149 #define ICQ5_SRV_UIN 0x0d
150 #define ICQ5_SRV_CHECKCODE 0x11
151 #define ICQ5_SRV_PARAM 0x15
152 #define ICQ5_SRV_HDRSIZE 0x15
154 #define SRV_ACK 0x000a
156 #define SRV_SILENT_TOO_LONG 0x001e
158 #define SRV_GO_AWAY 0x0028
160 #define SRV_NEW_UIN 0x0046
162 /* LOGIN_REPLY is very scary. It has a lot of fields that are undocumented
163 * Only the IP field makes sense */
164 #define SRV_LOGIN_REPLY 0x005a
165 #define SRV_LOGIN_REPLY_IP 0x000c
167 #define SRV_BAD_PASS 0x0064
169 #define SRV_USER_ONLINE 0x006e
170 #define SRV_USER_ONL_UIN 0x0000
171 #define SRV_USER_ONL_IP 0x0004
172 #define SRV_USER_ONL_PORT 0x0008
173 #define SRV_USER_ONL_REALIP 0x000c
174 #define SRV_USER_ONL_X1 0x0010
175 #define SRV_USER_ONL_STATUS 0x0013
176 #define SRV_USER_ONL_X2 0x0015
178 #define SRV_USER_OFFLINE 0x0078
179 #define SRV_USER_OFFLINE_UIN 0x0000
181 #define SRV_MULTI 0x0212
182 #define SRV_MULTI_NUM 0x0000
184 #define SRV_META_USER 0x03de
185 #define SRV_META_USER_SUBCMD 0x0000
186 #define SRV_META_USER_RESULT 0x0002
187 #define SRV_META_USER_DATA 0x0003
189 #define SRV_UPDATE_SUCCESS 0x01e0
191 #define SRV_UPDATE_FAIL 0x01ea
194 * ICQv5 SRV_META_USER subcommands
196 #define META_EX_USER_FOUND 0x0190
197 #define META_USER_FOUND 0x019a
198 #define META_ABOUT 0x00e6
199 #define META_USER_INFO 0x00c8
201 #define SRV_RECV_MESSAGE 0x00dc
202 #define SRV_RECV_MSG_UIN 0x0000
203 #define SRV_RECV_MSG_YEAR 0x0004
204 #define SRV_RECV_MSG_MONTH 0x0006
205 #define SRV_RECV_MSG_DAY 0x0007
206 #define SRV_RECV_MSG_HOUR 0x0008
207 #define SRV_RECV_MSG_MINUTE 0x0009
208 #define SRV_RECV_MSG_MSG_TYPE 0x000a
210 #define SRV_RAND_USER 0x024e
211 #define SRV_RAND_USER_UIN 0x0000
212 #define SRV_RAND_USER_IP 0x0004
213 #define SRV_RAND_USER_PORT 0x0008
214 #define SRV_RAND_USER_REAL_IP 0x000c
215 #define SRV_RAND_USER_CLASS 0x0010
216 #define SRV_RAND_USER_X1 0x0011
217 #define SRV_RAND_USER_STATUS 0x0015
218 #define SRV_RAND_USER_TCP_VER 0x0019
220 /* This message has the same structure as cmd_send_msg */
221 #define SRV_SYS_DELIVERED_MESS 0x0104
223 static const value_string serverMetaSubCmdCode
[] = {
224 { META_USER_FOUND
, "META_USER_FOUND" },
225 { META_EX_USER_FOUND
, "META_EX_USER_FOUND" },
226 { META_ABOUT
, "META_ABOUT" },
227 { META_USER_INFO
, "META_USER_INFO" },
231 static const value_string serverCmdCode
[] = {
232 { SRV_ACK
, "SRV_ACK" },
233 { SRV_SILENT_TOO_LONG
, "SRV_SILENT_TOO_LONG" },
234 { SRV_GO_AWAY
, "SRV_GO_AWAY" },
235 { SRV_NEW_UIN
, "SRV_NEW_UIN" },
236 { SRV_LOGIN_REPLY
, "SRV_LOGIN_REPLY" },
237 { SRV_BAD_PASS
, "SRV_BAD_PASS" },
238 { SRV_USER_ONLINE
, "SRV_USER_ONLINE" },
239 { SRV_USER_OFFLINE
, "SRV_USER_OFFLINE" },
240 { 130, "SRV_QUERY" },
241 { 140, "SRV_USER_FOUND" },
242 { 160, "SRV_END_OF_SEARCH" },
243 { 180, "SRV_NEW_USER" },
244 { 200, "SRV_UPDATE_EXT" },
245 { SRV_RECV_MESSAGE
, "SRV_RECV_MESSAGE" },
246 { 230, "SRV_END_OFFLINE_MESSAGES" },
247 { 240, "SRV_NOT_CONNECTED" },
248 { 250, "SRV_TRY_AGAIN" },
249 { SRV_SYS_DELIVERED_MESS
, "SRV_SYS_DELIVERED_MESS" },
250 { 280, "SRV_INFO_REPLY" },
251 { 290, "SRV_EXT_INFO_REPLY" },
252 { 420, "SRV_STATUS_UPDATE" },
253 { 450, "SRV_SYSTEM_MESSAGE" },
254 { SRV_UPDATE_SUCCESS
, "SRV_UPDATE_SUCCESS" },
255 { SRV_UPDATE_FAIL
, "SRV_UPDATE_FAIL" },
256 { 500, "SRV_AUTH_UPDATE" },
257 { SRV_MULTI
, "SRV_MULTI_PACKET" },
258 { 540, "SRV_END_CONTACTLIST_STATUS" },
259 { SRV_RAND_USER
, "SRV_RAND_USER" },
260 { SRV_META_USER
, "SRV_META_USER" },
264 #define MSG_TEXT 0x0001
265 #define MSG_URL 0x0004
266 #define MSG_AUTH_REQ 0x0006
267 #define MSG_AUTH 0x0008
268 #define MSG_USER_ADDED 0x000c
269 #define MSG_EMAIL 0x000e
270 #define MSG_CONTACTS 0x0013
272 #define STATUS_ONLINE 0x00000000
273 #define STATUS_AWAY 0x00000001
274 #define STATUS_DND 0x00000013
275 #define STATUS_INVISIBLE 0x00000100
276 #define STATUS_OCCUPIED 0x00000010
277 #define STATUS_NA 0x00000004
278 #define STATUS_CHAT 0x00000020
280 /* Offsets for all packets measured from the start of the payload; i.e.
281 * with the ICQ header removed
283 #define CMD_ACK 0x000a
284 #define CMD_ACK_RANDOM 0x0000
286 #define CMD_SEND_MSG 0x010E
287 #define CMD_SEND_MSG_RECV_UIN 0x0000
288 #define CMD_SEND_MSG_MSG_TYPE 0x0004
289 #define CMD_SEND_MSG_MSG_LEN 0x0006
290 #define CMD_SEND_MSG_MSG_TEXT 0x0008
291 /* The rest of the packet should be a null-term string */
293 #define CMD_LOGIN 0x03E8
294 #define CMD_LOGIN_TIME 0x0000
295 #define CMD_LOGIN_PORT 0x0004
296 #define CMD_LOGIN_PASSLEN 0x0008
297 #define CMD_LOGIN_PASSWD 0x000A
298 /* The password is variable length; so when we've decoded the passwd,
299 * the structure starts counting at 0 again.
301 #define CMD_LOGIN_IP 0x0004
302 #define CMD_LOGIN_STATUS 0x0009
304 #define CMD_CONTACT_LIST 0x0406
305 #define CMD_CONTACT_LIST_NUM 0x0000
307 #define CMD_USER_META 0x064a
309 #define CMD_REG_NEW_USER 0x03fc
311 #define CMD_ACK_MESSAGES 0x0442
312 #define CMD_ACK_MESSAGES_RANDOM 0x0000
314 #define CMD_KEEP_ALIVE 0x042e
315 #define CMD_KEEP_ALIVE_RANDOM 0x0000
317 #define CMD_SEND_TEXT_CODE 0x0438
318 #define CMD_SEND_TEXT_CODE_LEN 0x0000
319 #define CMD_SEND_TEXT_CODE_TEXT 0x0002
321 #define CMD_MSG_TO_NEW_USER 0x0456
323 #define CMD_QUERY_SERVERS 0x04ba
325 #define CMD_QUERY_ADDONS 0x04c4
327 #define CMD_STATUS_CHANGE 0x04d8
328 #define CMD_STATUS_CHANGE_STATUS 0x0000
330 #define CMD_ADD_TO_LIST 0x053c
331 #define CMD_ADD_TO_LIST_UIN 0x0000
333 #define CMD_RAND_SEARCH 0x056e
334 #define CMD_RAND_SEARCH_GROUP 0x0000
336 #define CMD_META_USER 0x064a
338 static const value_string msgTypeCode
[] = {
339 { MSG_TEXT
, "MSG_TEXT" },
340 { MSG_URL
, "MSG_URL" },
341 { MSG_AUTH_REQ
, "MSG_AUTH_REQ" },
342 { MSG_AUTH
, "MSG_AUTH" },
343 { MSG_USER_ADDED
, "MSG_USER_ADDED" },
344 { MSG_EMAIL
, "MSG_EMAIL" },
345 { MSG_CONTACTS
, "MSG_CONTACTS" },
349 static const value_string statusCode
[] = {
350 { STATUS_ONLINE
, "ONLINE" },
351 { STATUS_AWAY
, "AWAY" },
352 { STATUS_DND
, "DND" },
353 { STATUS_INVISIBLE
, "INVISIBLE" },
354 { STATUS_OCCUPIED
, "OCCUPIED" },
356 { STATUS_CHAT
, "Free for Chat" },
360 static const value_string clientCmdCode
[] = {
361 { CMD_ACK
, "CMD_ACK" },
362 { CMD_SEND_MSG
, "CMD_SEND_MESSAGE" },
363 { CMD_LOGIN
, "CMD_LOGIN" },
364 { CMD_REG_NEW_USER
, "CMD_REG_NEW_USER" },
365 { 1030, "CMD_CONTACT_LIST" },
366 { 1050, "CMD_SEARCH_UIN" },
367 { 1060, "CMD_SEARCH_USER" },
368 { 1070, "CMD_KEEP_ALIVE" },
369 { CMD_SEND_TEXT_CODE
, "CMD_SEND_TEXT_CODE" },
370 { CMD_ACK_MESSAGES
, "CMD_ACK_MESSAGES" },
371 { 1100, "CMD_LOGIN_1" },
372 { CMD_MSG_TO_NEW_USER
, "CMD_MSG_TO_NEW_USER" },
373 { 1120, "CMD_INFO_REQ" },
374 { 1130, "CMD_EXT_INFO_REQ" },
375 { 1180, "CMD_CHANGE_PW" },
376 { 1190, "CMD_NEW_USER_INFO" },
377 { 1200, "CMD_UPDATE_EXT_INFO" },
378 { CMD_QUERY_SERVERS
, "CMD_QUERY_SERVERS" },
379 { CMD_QUERY_ADDONS
, "CMD_QUERY_ADDONS" },
380 { CMD_STATUS_CHANGE
, "CMD_STATUS_CHANGE" },
381 { 1260, "CMD_NEW_USER_1" },
382 { 1290, "CMD_UPDATE_INFO" },
383 { 1300, "CMD_AUTH_UPDATE" },
384 { 1310, "CMD_KEEP_ALIVE2" },
385 { 1320, "CMD_LOGIN_2" },
386 { CMD_ADD_TO_LIST
, "CMD_ADD_TO_LIST" },
387 { 1380, "CMD_RAND_SET" },
388 { CMD_RAND_SEARCH
, "CMD_RAND_SEARCH" },
389 { CMD_META_USER
, "CMD_META_USER" },
390 { 1700, "CMD_INVIS_LIST" },
391 { 1710, "CMD_VIS_LIST" },
392 { 1720, "CMD_UPDATE_LIST" },
397 static const value_string group_vals
[] = {
403 { 6, "20 Something" },
404 { 7, "30 Something" },
405 { 8, "40 Something" },
406 { 9, "50 or worse" },
407 { 10, "Man want women" },
408 { 11, "Women want men" },
414 * All ICQv5 decryption code thanx to Sebastien Dault (daus01@gel.usherb.ca)
416 static const unsigned char
418 0x59, 0x60, 0x37, 0x6B, 0x65, 0x62, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x60, 0x57, 0x5B, 0x3D,
419 0x5E, 0x34, 0x6D, 0x36, 0x50, 0x3F, 0x6F, 0x67, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x47, 0x63, 0x39,
420 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x43, 0x69, 0x48, 0x33, 0x31, 0x64, 0x35, 0x5A, 0x4A, 0x42,
421 0x56, 0x40, 0x67, 0x53, 0x41, 0x07, 0x6C, 0x49, 0x58, 0x3B, 0x4D, 0x46, 0x68, 0x43, 0x69, 0x48,
422 0x33, 0x31, 0x44, 0x65, 0x62, 0x46, 0x48, 0x53, 0x41, 0x07, 0x6C, 0x69, 0x48, 0x33, 0x51, 0x54,
423 0x5D, 0x4E, 0x6C, 0x49, 0x38, 0x4B, 0x55, 0x4A, 0x62, 0x46, 0x48, 0x33, 0x51, 0x34, 0x6D, 0x36,
424 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x63, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64, 0x35, 0x5A,
425 0x6A, 0x52, 0x6E, 0x3C, 0x51, 0x34, 0x6D, 0x36, 0x50, 0x5F, 0x5F, 0x3F, 0x4F, 0x37, 0x4B, 0x35,
426 0x5A, 0x4A, 0x62, 0x66, 0x58, 0x3B, 0x4D, 0x66, 0x58, 0x5B, 0x5D, 0x4E, 0x6C, 0x49, 0x58, 0x3B,
427 0x4D, 0x66, 0x58, 0x3B, 0x4D, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64,
428 0x55, 0x6A, 0x32, 0x3E, 0x44, 0x45, 0x52, 0x6E, 0x3C, 0x31, 0x64, 0x55, 0x6A, 0x52, 0x4E, 0x6C,
429 0x69, 0x48, 0x53, 0x61, 0x4C, 0x39, 0x30, 0x6F, 0x47, 0x63, 0x59, 0x60, 0x57, 0x5B, 0x3D, 0x3E,
430 0x64, 0x35, 0x3A, 0x3A, 0x5A, 0x6A, 0x52, 0x4E, 0x6C, 0x69, 0x48, 0x53, 0x61, 0x6C, 0x49, 0x58,
431 0x3B, 0x4D, 0x46, 0x68, 0x63, 0x39, 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x67, 0x53, 0x41, 0x25, 0x41,
432 0x3C, 0x51, 0x54, 0x3D, 0x5E, 0x54, 0x5D, 0x4E, 0x4C, 0x39, 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F,
433 0x47, 0x43, 0x69, 0x48, 0x33, 0x51, 0x54, 0x5D, 0x6E, 0x3C, 0x31, 0x64, 0x35, 0x5A, 0x00, 0x00 };
437 get_v5key(uint32_t code
, int len
)
439 uint32_t a1
, a2
, a3
, a4
, a5
;
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(unsigned char *bfr
, uint32_t size
,uint32_t key
)
466 for (i
=ICQ5_CL_SESSIONID
; i
< size
; i
+=4 ) {
467 k
= key
+table_v5
[i
&0xff];
469 bfr
[i
] ^= (unsigned char)(k
& 0xff);
470 bfr
[i
+1] ^= (unsigned char)((k
& 0xff00)>>8);
473 bfr
[i
+2] ^= (unsigned char)((k
& 0xff0000)>>16);
474 bfr
[i
+3] ^= (unsigned char)((k
& 0xff000000)>>24);
480 icqv5_decode_msgType(proto_tree
*tree
, tvbuff_t
*tvb
, int offset
, int size
,
483 proto_item
*msg_item
;
488 int sz
; /* Size of the current element */
490 static int * const url_field_descr
[] = {
494 #define N_URL_FIELDS array_length(url_field_descr)
495 static int * const email_field_descr
[] = {
503 #define N_EMAIL_FIELDS array_length(email_field_descr)
504 static int * const auth_req_field_descr
[] = {
512 #define N_AUTH_REQ_FIELDS array_length(auth_req_field_descr)
513 static int * const user_added_field_descr
[] = {
519 #define N_USER_ADDED_FIELDS array_length(user_added_field_descr)
521 msgType
= tvb_get_letohs(tvb
, offset
);
522 subtree
= proto_tree_add_subtree_format(tree
, tvb
, offset
, size
, ett_icq_body_parts
, NULL
,
523 "%s Message", val_to_str_const(msgType
, msgTypeCode
, "Unknown"));
525 msg_item
= proto_tree_add_item(subtree
, hf_icq_msg_type
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
528 if (msgType
!= MSG_AUTH
) {
530 * XXX - does a MSG_AUTH message really have 3 bytes of information
531 * rather than a length field?
533 proto_tree_add_item(subtree
, hf_icq_msg_length
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
539 case 0xffff: /* Field unknown */
542 expert_add_info_format(pinfo
, msg_item
, &ei_icq_unknown_command
,
543 "Unknown msgType: %u (0x%x)", msgType
, msgType
);
546 proto_tree_add_item(subtree
, hf_icq_msg
, tvb
, offset
, left
, ENC_ASCII
);
549 for (n
= 0; n
< N_URL_FIELDS
; n
++) {
550 if (n
!= N_URL_FIELDS
- 1) {
551 sep_offset
= tvb_find_uint8(tvb
, offset
, left
, 0xfe);
552 sz
= sep_offset
- offset
+ 1;
557 proto_tree_add_item(subtree
, *url_field_descr
[n
], tvb
, offset
, sz
, ENC_ASCII
|ENC_NA
);
559 proto_tree_add_string_format_value(subtree
, *url_field_descr
[n
], tvb
, offset
, 0,
567 for (n
= 0; n
< N_EMAIL_FIELDS
; n
++) {
568 if (n
!= N_EMAIL_FIELDS
- 1) {
569 sep_offset
= tvb_find_uint8(tvb
, offset
, left
, 0xfe);
570 sz
= sep_offset
- offset
+ 1;
575 proto_tree_add_item(subtree
, *email_field_descr
[n
], tvb
, offset
, sz
, ENC_ASCII
|ENC_NA
);
577 proto_tree_add_string_format_value(subtree
, *email_field_descr
[n
], tvb
, offset
, 0,
587 /* Three bytes, first is a char signifying success */
588 unsigned char auth_suc
;
590 auth_suc
= tvb_get_uint8(tvb
, offset
);
591 proto_tree_add_uint_format_value(subtree
, hf_icq_msg_authorization
, tvb
, offset
, 1,
592 auth_suc
, "(%u) %s",auth_suc
,
593 (auth_suc
==0)?"Denied":"Allowed");
595 proto_tree_add_item(subtree
, hf_icq_x1
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
599 for (n
= 0; n
< N_AUTH_REQ_FIELDS
; n
++) {
600 if (n
!= N_AUTH_REQ_FIELDS
- 1) {
601 sep_offset
= tvb_find_uint8(tvb
, offset
, left
, 0xfe);
602 sz
= sep_offset
- offset
+ 1;
607 proto_tree_add_item(subtree
, *auth_req_field_descr
[n
], tvb
, offset
, sz
, ENC_ASCII
|ENC_NA
);
609 proto_tree_add_string_format_value(subtree
, *auth_req_field_descr
[n
], tvb
, offset
, 0,
617 for (n
= 0; n
< N_USER_ADDED_FIELDS
; n
++) {
618 if (n
!= N_USER_ADDED_FIELDS
- 1) {
619 sep_offset
= tvb_find_uint8(tvb
, offset
, left
, 0xfe);
620 sz
= sep_offset
- offset
+ 1;
625 proto_tree_add_item(subtree
, *user_added_field_descr
[n
], tvb
, offset
, sz
, ENC_ASCII
|ENC_NA
);
627 proto_tree_add_string_format_value(subtree
, *user_added_field_descr
[n
], tvb
, offset
, 0,
637 int sz_local
= 0; /* Size of the current element */
638 int n_local
= 0; /* The nth element */
642 sep_offset
= tvb_find_uint8(tvb
, offset
, left
, 0xfe);
643 if (sep_offset
!= -1) {
644 sz_local
= sep_offset
- offset
+ 1;
652 /* The first element is the number of Nick/UIN pairs follow */
653 proto_tree_add_item(subtree
, hf_icq_num_uin_pairs
, tvb
, offset
, sz_local
, ENC_ASCII
);
660 sep_offset_prev
= sep_offset
;
661 sep_offset
= tvb_find_uint8(tvb
, sep_offset_prev
, left
, 0xfe);
662 if (sep_offset
!= -1)
663 sz_local
= sep_offset
- offset
+ 1;
668 contact
= tvb_get_string_enc(pinfo
->pool
, tvb
, sep_offset_prev
+ 1, sz_local
, ENC_ASCII
);
669 proto_tree_add_string_format(subtree
, hf_icq_msg_contact
, tvb
, offset
, sz_local
+ svsz
,
671 tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, svsz
, ENC_ASCII
),
676 left
-= (sz_local
+1);
677 offset
= sep_offset
+ 1;
684 /*********************************
688 *********************************/
690 icqv5_cmd_send_text_code(proto_tree
*tree
, /* Tree to put the data in */
691 tvbuff_t
*tvb
, /* Decrypted packet content */
692 int offset
) /* Offset from the start of the packet to the content */
694 proto_tree
*subtree
= tree
;
697 len
= tvb_get_letohs(tvb
, offset
+CMD_SEND_TEXT_CODE_LEN
);
698 proto_tree_add_item(subtree
, hf_icq_text_code_length
, tvb
, offset
+ CMD_SEND_TEXT_CODE_LEN
, 2, ENC_LITTLE_ENDIAN
);
701 proto_tree_add_item(subtree
, hf_icq_text_code
, tvb
, offset
+ CMD_SEND_TEXT_CODE_TEXT
, len
, ENC_ASCII
);
704 proto_tree_add_item(subtree
, hf_icq_x1
, tvb
, offset
+ CMD_SEND_TEXT_CODE_TEXT
+ len
, 2, ENC_LITTLE_ENDIAN
);
708 icqv5_cmd_send_msg(proto_tree
*tree
, tvbuff_t
*tvb
, int offset
, int size
,
711 proto_tree_add_item(tree
, hf_icq_receiver_uin
, tvb
, offset
+ CMD_SEND_MSG_RECV_UIN
, 4, ENC_LITTLE_ENDIAN
);
714 icqv5_decode_msgType(tree
, tvb
, offset
+ CMD_SEND_MSG_MSG_TYPE
,
719 icqv5_cmd_login(proto_tree
*tree
, tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
)
721 proto_tree
*subtree
= tree
;
727 theTime
= tvb_get_letohl(tvb
, offset
+ CMD_LOGIN_TIME
);
728 aTime
= abs_time_secs_to_str(pinfo
->pool
, theTime
, ABSOLUTE_TIME_LOCAL
, true);
729 proto_tree_add_uint_format_value(subtree
, hf_icq_login_time
, tvb
, offset
+ CMD_LOGIN_TIME
, 4,
730 (uint32_t)theTime
, "%u = %s", (uint32_t)theTime
, aTime
);
731 proto_tree_add_item(subtree
, hf_icq_login_port
, tvb
, offset
+ CMD_LOGIN_PORT
, 4, ENC_LITTLE_ENDIAN
);
732 passwdLen
= tvb_get_letohs(tvb
, offset
+ CMD_LOGIN_PASSLEN
);
733 proto_tree_add_item(subtree
, hf_icq_login_password
, tvb
, offset
+ CMD_LOGIN_PASSLEN
, 2 + passwdLen
, ENC_ASCII
);
734 proto_tree_add_item(subtree
, hf_icq_login_ip
, tvb
, offset
+ CMD_LOGIN_PASSWD
+ passwdLen
+ CMD_LOGIN_IP
, 4, ENC_BIG_ENDIAN
);
735 proto_tree_add_item(subtree
, hf_icq_status
, tvb
, offset
+ CMD_LOGIN_PASSWD
+ passwdLen
+ CMD_LOGIN_STATUS
, 4, ENC_LITTLE_ENDIAN
);
740 icqv5_cmd_contact_list(proto_tree
*tree
, tvbuff_t
*tvb
, int offset
)
747 num
= tvb_get_uint8(tvb
, offset
+ CMD_CONTACT_LIST_NUM
);
748 proto_tree_add_item(tree
, hf_icq_number_of_uins
, tvb
, offset
+ CMD_CONTACT_LIST
, 1, ENC_NA
);
750 * A sequence of num times UIN follows
752 offset
+= (CMD_CONTACT_LIST_NUM
+ 1);
753 for (i
= 0; i
< num
; i
++) {
754 uin
= tvb_get_letohl(tvb
, offset
);
755 proto_tree_add_uint_format(tree
, hf_icq_uin
, tvb
, offset
, 4,
756 uin
, "UIN[%d]: %u", i
, uin
);
762 /**********************
766 **********************
769 icqv5_srv_user_online(proto_tree
*tree
,/* Tree to put the data in */
770 tvbuff_t
*tvb
, /* Tvbuff with packet */
771 int offset
) /* Offset from the start of the packet to the content */
773 proto_tree
*subtree
= tree
;
776 proto_tree_add_item(subtree
, hf_icq_uin
, tvb
, offset
+ SRV_USER_ONL_UIN
, 4, ENC_LITTLE_ENDIAN
);
777 proto_tree_add_item(subtree
, hf_icq_user_online_ip
, tvb
, offset
+ SRV_USER_ONL_IP
, 4, ENC_BIG_ENDIAN
);
778 proto_tree_add_item(subtree
, hf_icq_user_online_port
, tvb
, offset
+ SRV_USER_ONL_PORT
, 4, ENC_LITTLE_ENDIAN
);
779 proto_tree_add_item(subtree
, hf_icq_user_online_realip
, tvb
, offset
+ SRV_USER_ONL_REALIP
, 4, ENC_BIG_ENDIAN
);
780 proto_tree_add_item(subtree
, hf_icq_status
, tvb
, offset
+ SRV_USER_ONL_STATUS
, 2, ENC_LITTLE_ENDIAN
);
782 * Kojak: Hypothesis is that this field might be an encoding for the
783 * version used by the UIN that changed. To test this, I included
784 * this line to the code.
786 proto_tree_add_item(subtree
, hf_icq_user_online_version
, tvb
, offset
+ SRV_USER_ONL_X2
, 4, ENC_LITTLE_ENDIAN
);
791 // NOLINTNEXTLINE(misc-no-recursion)
792 icqv5_srv_multi(proto_tree
*tree
, /* Tree to put the data in */
793 tvbuff_t
*tvb
, /* Packet content */
794 int offset
, /* Offset from the start of the packet to the content */
801 num
= tvb_get_uint8(tvb
, offset
+ SRV_MULTI_NUM
);
802 proto_tree_add_item(tree
, hf_icq_multi_num_packets
, tvb
, offset
+ SRV_MULTI_NUM
, 1, ENC_NA
);
804 * A sequence of num times ( pktsize, packetData) follows
806 offset
+= (SRV_MULTI_NUM
+ 1);
807 for (i
= 0; i
< num
; i
++) {
808 pktSz
= tvb_get_letohs(tvb
, offset
);
810 // We recurse here, but we'll run out of packet before we run out of stack.
811 dissect_icqv5Server(tvb
, offset
, pinfo
, tree
, pktSz
);
817 icqv5_srv_meta_user(proto_tree
*tree
, /* Tree to put the data in */
818 tvbuff_t
*tvb
, /* Tvbuff with packet */
819 int offset
, /* Offset from the start of the packet to the content */
820 int size _U_
, /* Number of chars left to do */
826 unsigned char result
;
828 subcmd
= tvb_get_letohs(tvb
, offset
+ SRV_META_USER_SUBCMD
);
829 ti
= proto_tree_add_item(tree
, hf_icq_meta_user_subcmd
, tvb
, offset
+ SRV_META_USER_SUBCMD
, 2, ENC_LITTLE_ENDIAN
);
830 sstree
= proto_item_add_subtree(ti
, ett_icq_body_parts
);
831 result
= tvb_get_uint8(tvb
, offset
+ SRV_META_USER_RESULT
);
832 proto_tree_add_uint_format_value(sstree
, hf_icq_meta_user_result
, tvb
, offset
+ SRV_META_USER_RESULT
,
833 result
, 1, "%s", (result
==0x0a)?"Success":"Failure");
835 /* Skip the META_USER header */
839 case META_EX_USER_FOUND
:
841 /* This is almost the same as META_USER_FOUND,
842 * however, there's an extra length field
845 /* Read the length field */
846 proto_tree_add_item(sstree
, hf_icq_meta_user_length
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
851 case META_USER_FOUND
:
853 /* The goto mentioned in this block should be local to this
854 * block if C'd allow it.
856 * They are used to "implement" a poorman's exception handling
863 proto_tree_add_item(sstree
, hf_icq_uin
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
866 proto_tree_add_item_ret_length(sstree
, hf_icq_nickname_uint_string
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
868 proto_tree_add_item_ret_length(sstree
, hf_icq_first_name_uint_string
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
870 proto_tree_add_item_ret_length(sstree
, hf_icq_last_name_uint_string
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
872 proto_tree_add_item_ret_length(sstree
, hf_icq_email_uint_string
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
875 /* Get the authorize setting */
876 auth
= tvb_get_uint8(tvb
, offset
);
877 proto_tree_add_uint_format_value(sstree
, hf_icq_meta_user_found_authorization
, tvb
, offset
, 1,
878 auth
, "%s", (auth
==0x01)?"Necessary":"Who needs it");
881 proto_tree_add_item(sstree
, hf_icq_meta_user_x2
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
884 proto_tree_add_item(sstree
, hf_icq_meta_user_x3
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
889 /* Get the about information */
890 proto_tree_add_item(sstree
, hf_icq_meta_user_about
, tvb
, offset
,
891 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
);
899 proto_tree_add_item(sstree
, hf_icq_uin
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
904 * Get every field from the description
906 proto_tree_add_item_ret_length(sstree
, hf_icq_nickname_uint_string
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
908 proto_tree_add_item_ret_length(sstree
, hf_icq_first_name_uint_string
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
910 proto_tree_add_item_ret_length(sstree
, hf_icq_last_name_uint_string
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
912 proto_tree_add_item_ret_length(sstree
, hf_icq_primary_email
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
914 proto_tree_add_item_ret_length(sstree
, hf_icq_secondary_email
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
916 proto_tree_add_item_ret_length(sstree
, hf_icq_old_email
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
918 proto_tree_add_item_ret_length(sstree
, hf_icq_city
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
920 proto_tree_add_item_ret_length(sstree
, hf_icq_state
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
922 proto_tree_add_item_ret_length(sstree
, hf_icq_phone
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
924 proto_tree_add_item_ret_length(sstree
, hf_icq_fax
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
926 proto_tree_add_item_ret_length(sstree
, hf_icq_street
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
928 proto_tree_add_item_ret_length(sstree
, hf_icq_cellphone
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
930 proto_tree_add_item_ret_length(sstree
, hf_icq_zip
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
|ENC_ASCII
, &len
);
933 /* Get country code */
934 proto_tree_add_item(sstree
, hf_icq_meta_user_countrycode
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
936 /* Get the timezone setting */
937 proto_tree_add_item(sstree
, hf_icq_meta_user_timezone
, tvb
, offset
, 1, ENC_NA
);
939 /* Get the authorize setting */
940 proto_tree_add_item(sstree
, hf_icq_meta_user_info_authorization
, tvb
, offset
, 1, ENC_NA
);
942 /* Get the webaware setting */
943 proto_tree_add_item(sstree
, hf_icq_meta_user_webaware
, tvb
, offset
, 1, ENC_NA
);
945 /* Get the authorize setting */
946 proto_tree_add_item(sstree
, hf_icq_meta_user_hideip
, tvb
, offset
, 1, ENC_NA
);
950 /* This information is already printed in the tree */
951 expert_add_info_format(pinfo
, ti
, &ei_icq_unknown_meta_subcmd
,
952 "Unknown Meta subcmd: 0x%x", subcmd
);
958 icqv5_srv_recv_message(proto_tree
*tree
, /* Tree to put the data in */
959 tvbuff_t
*tvb
, /* Packet content */
960 int offset
, /* Offset from the start of the packet to the content */
961 int size
, /* Number of chars left to do */
970 proto_tree_add_item(tree
, hf_icq_uin
, tvb
, offset
+ SRV_RECV_MSG_UIN
,
971 4, ENC_LITTLE_ENDIAN
);
972 year
= tvb_get_letohs(tvb
, offset
+ SRV_RECV_MSG_YEAR
);
973 month
= tvb_get_uint8(tvb
, offset
+ SRV_RECV_MSG_MONTH
);
974 day
= tvb_get_uint8(tvb
, offset
+ SRV_RECV_MSG_DAY
);
975 hour
= tvb_get_uint8(tvb
, offset
+ SRV_RECV_MSG_HOUR
);
976 minute
= tvb_get_uint8(tvb
, offset
+ SRV_RECV_MSG_MINUTE
);
978 proto_tree_add_bytes_format_value(tree
, hf_icq_recv_time
, tvb
, offset
+ SRV_RECV_MSG_YEAR
,
979 2 + 4, NULL
, "%u-%u-%u %02u:%02u",
980 day
, month
, year
, hour
, minute
);
981 icqv5_decode_msgType(tree
, tvb
, offset
+ SRV_RECV_MSG_MSG_TYPE
,
986 icqv5_srv_rand_user(proto_tree
*tree
, /* Tree to put the data in */
987 tvbuff_t
*tvb
, /* Tvbuff with packet */
988 int offset
) /* Offset from the start of the packet to the content */
990 proto_tree
*subtree
= tree
;
995 proto_tree_add_item(subtree
, hf_icq_uin
, tvb
, offset
+ SRV_RAND_USER_UIN
,
996 4, ENC_LITTLE_ENDIAN
);
998 proto_tree_add_item(subtree
, hf_icq_rand_user_ip
, tvb
, offset
+ SRV_RAND_USER_IP
, 4, ENC_BIG_ENDIAN
);
999 /* uint16_t portNum */
1000 /* XXX - 16 bits, or 32 bits? */
1001 proto_tree_add_item(subtree
, hf_icq_rand_user_port
, tvb
, offset
+ SRV_RAND_USER_PORT
, 4, ENC_LITTLE_ENDIAN
);
1002 /* uint32_t realIP */
1003 proto_tree_add_item(subtree
, hf_icq_rand_user_realip
, tvb
, offset
+ SRV_RAND_USER_REAL_IP
, 4, ENC_BIG_ENDIAN
);
1004 /* uint8_t Communication Class */
1005 commClass
= tvb_get_uint8(tvb
, offset
+ SRV_RAND_USER_CLASS
);
1006 proto_tree_add_uint_format_value(subtree
, hf_icq_rand_user_class
, tvb
, offset
+ SRV_RAND_USER_CLASS
,
1007 1, commClass
, "%s", (commClass
!=4)?"User to User":"Through Server");
1008 /* uint32_t status */
1009 /* XXX - 16 bits, or 32 bits? */
1010 proto_tree_add_item(subtree
, hf_icq_status
, tvb
, offset
+ SRV_RAND_USER_STATUS
, 4, ENC_LITTLE_ENDIAN
);
1012 /* uint16_t tcpVersion */
1013 proto_tree_add_item(subtree
, hf_icq_rand_user_tcpversion
, tvb
, offset
+ SRV_RAND_USER_TCP_VER
, 2, ENC_LITTLE_ENDIAN
);
1018 * Dissect all the v5 client traffic. This is encrypted, so be careful.
1021 dissect_icqv5Client(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
1023 proto_tree
*icq_header_tree
, *icq_body_tree
;
1024 proto_item
*ti
, *cmd_item
;
1026 int pktsize
; /* The actual size of the ICQ content */
1027 int capturedsize
; /* The captured size of the ICQ content */
1028 uint32_t rounded_size
;
1031 uint8_t *decr_pd
; /* Decrypted content */
1034 pktsize
= tvb_reported_length(tvb
);
1035 capturedsize
= tvb_captured_length(tvb
);
1037 /* Get the encryption key */
1038 code
= tvb_get_letohl(tvb
, ICQ5_CL_CHECKCODE
);
1039 key
= get_v5key(code
, pktsize
);
1042 * Make a copy of the packet data, and decrypt it.
1043 * The decryption processes 4 bytes at a time, and starts at
1044 * an offset of ICQ5_CL_SESSIONID (which isn't a multiple of 4),
1045 * so we make sure that there are
1047 * (ICQ5_CL_SESSIONID + a multiple of 4)
1049 * bytes in the buffer.
1051 rounded_size
= ((((capturedsize
- ICQ5_CL_SESSIONID
) + 3)/4)*4) + ICQ5_CL_SESSIONID
;
1052 /* rounded_size might exceed the tvb bounds so we can't just use tvb_memdup here. */
1053 decr_pd
= (uint8_t *)wmem_alloc(pinfo
->pool
, rounded_size
);
1054 tvb_memcpy(tvb
, decr_pd
, 0, capturedsize
);
1055 decrypt_v5(decr_pd
, rounded_size
, key
);
1057 /* Allocate a new tvbuff, referring to the decrypted data. */
1058 decr_tvb
= tvb_new_child_real_data(tvb
, decr_pd
, capturedsize
, pktsize
);
1060 /* Add the decrypted data to the data source list. */
1061 add_new_data_source(pinfo
, decr_tvb
, "Decrypted");
1063 cmd
= tvb_get_letohs(decr_tvb
, ICQ5_CL_CMD
);
1065 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "ICQv5 %s", val_to_str_const(cmd
, clientCmdCode
, "Unknown"));
1067 icq_header_tree
= proto_tree_add_subtree(tree
, tvb
, 0, ICQ5_CL_HDRSIZE
, ett_icq_header
, NULL
, "Header");
1069 ti
= proto_tree_add_boolean(icq_header_tree
, hf_icq_type
, tvb
, 0, 0, ICQ5_CLIENT
);
1070 proto_item_set_generated(ti
);
1072 proto_tree_add_item(icq_header_tree
, hf_icq_version
, tvb
, ICQ_VERSION
, 2, ENC_LITTLE_ENDIAN
);
1073 proto_tree_add_item(icq_header_tree
, hf_icq_uin
, tvb
, ICQ5_CL_UIN
, 4, ENC_LITTLE_ENDIAN
);
1074 proto_tree_add_item(icq_header_tree
, hf_icq_sessionid
, decr_tvb
, ICQ5_CL_SESSIONID
, 4, ENC_LITTLE_ENDIAN
);
1075 cmd_item
= proto_tree_add_item(icq_header_tree
, hf_icq_client_cmd
, decr_tvb
, ICQ5_CL_CMD
, 2, ENC_LITTLE_ENDIAN
);
1076 proto_tree_add_item(icq_header_tree
, hf_icq_seqnum1
, decr_tvb
, ICQ5_CL_SEQNUM1
, 2, ENC_LITTLE_ENDIAN
);
1077 proto_tree_add_item(icq_header_tree
, hf_icq_seqnum2
, decr_tvb
, ICQ5_CL_SEQNUM2
, 2, ENC_LITTLE_ENDIAN
);
1078 proto_tree_add_item(icq_header_tree
, hf_icq_checkcode
, tvb
, ICQ5_CL_CHECKCODE
, 4, ENC_LITTLE_ENDIAN
);
1079 ti
= proto_tree_add_uint(icq_header_tree
, hf_icq_checkcode_key
, tvb
, ICQ5_CL_CHECKCODE
, 4, key
);
1080 proto_item_set_generated(ti
);
1082 icq_body_tree
= proto_tree_add_subtree(tree
, decr_tvb
, ICQ5_CL_HDRSIZE
, pktsize
- ICQ5_CL_HDRSIZE
, ett_icq_body
, NULL
, "Body");
1086 proto_tree_add_item(icq_body_tree
, hf_icq_ack_random
, decr_tvb
, ICQ5_CL_HDRSIZE
+ CMD_ACK_RANDOM
, 4, ENC_LITTLE_ENDIAN
);
1089 case CMD_MSG_TO_NEW_USER
:
1090 icqv5_cmd_send_msg(icq_body_tree
, decr_tvb
, ICQ5_CL_HDRSIZE
,
1091 pktsize
- ICQ5_CL_HDRSIZE
, pinfo
);
1093 case CMD_RAND_SEARCH
:
1094 proto_tree_add_item(icq_body_tree
, hf_icq_group
, decr_tvb
, ICQ5_CL_HDRSIZE
+ CMD_RAND_SEARCH_GROUP
, 4, ENC_LITTLE_ENDIAN
);
1097 icqv5_cmd_login(icq_body_tree
, decr_tvb
, ICQ5_CL_HDRSIZE
, pinfo
);
1099 case CMD_SEND_TEXT_CODE
:
1100 icqv5_cmd_send_text_code(icq_body_tree
, decr_tvb
, ICQ5_CL_HDRSIZE
);
1102 case CMD_STATUS_CHANGE
:
1103 proto_tree_add_item(icq_body_tree
, hf_icq_status
, decr_tvb
, ICQ5_CL_HDRSIZE
+ CMD_STATUS_CHANGE_STATUS
, 4, ENC_LITTLE_ENDIAN
);
1105 case CMD_ACK_MESSAGES
:
1106 proto_tree_add_item(icq_body_tree
, hf_icq_ack_random
, decr_tvb
, ICQ5_CL_HDRSIZE
+ CMD_ACK_MESSAGES_RANDOM
, 4, ENC_LITTLE_ENDIAN
);
1108 case CMD_KEEP_ALIVE
:
1109 proto_tree_add_item(icq_body_tree
, hf_icq_keep_alive_random
, decr_tvb
, ICQ5_CL_HDRSIZE
+ CMD_KEEP_ALIVE_RANDOM
, 4, ENC_LITTLE_ENDIAN
);
1111 case CMD_ADD_TO_LIST
:
1112 proto_tree_add_item(icq_body_tree
, hf_icq_uin
, decr_tvb
, ICQ5_CL_HDRSIZE
+ CMD_ADD_TO_LIST_UIN
, 4, ENC_LITTLE_ENDIAN
);
1114 case CMD_CONTACT_LIST
:
1115 icqv5_cmd_contact_list(icq_body_tree
, decr_tvb
, ICQ5_CL_HDRSIZE
);
1118 case CMD_REG_NEW_USER
:
1119 case CMD_QUERY_SERVERS
:
1120 case CMD_QUERY_ADDONS
:
1121 proto_tree_add_item(icq_body_tree
, hf_icq_no_parameters
, tvb
, ICQ5_CL_HDRSIZE
, 0, ENC_NA
);
1124 expert_add_info(pinfo
, cmd_item
, &ei_icq_unknown_command
);
1130 // NOLINTNEXTLINE(misc-no-recursion)
1131 dissect_icqv5Server(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1132 proto_tree
*tree
, int pktsize
)
1134 /* Server traffic is easy, not encrypted */
1135 proto_tree
*icq_header_tree
, *icq_body_tree
;
1136 proto_item
*ti
, *cmd_item
;
1138 uint16_t cmd
= tvb_get_letohs(tvb
, offset
+ ICQ5_SRV_CMD
);
1140 if (pktsize
== -1) {
1141 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "ICQv5 %s", val_to_str_const(cmd
, serverCmdCode
, "Unknown"));
1142 pktsize
= tvb_reported_length(tvb
);
1145 icq_header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, ICQ5_SRV_HDRSIZE
, ett_icq_header
, NULL
, "Header");
1147 ti
= proto_tree_add_boolean(icq_header_tree
, hf_icq_type
, tvb
, 0, 0, ICQ5_SERVER
);
1148 proto_item_set_generated(ti
);
1150 proto_tree_add_item(icq_header_tree
, hf_icq_version
, tvb
, offset
+ ICQ_VERSION
, 2, ENC_LITTLE_ENDIAN
);
1151 proto_tree_add_item(icq_header_tree
, hf_icq_sessionid
, tvb
, offset
+ ICQ5_SRV_SESSIONID
, 4, ENC_LITTLE_ENDIAN
);
1152 cmd_item
= proto_tree_add_item(icq_header_tree
, hf_icq_server_cmd
, tvb
, offset
+ ICQ5_SRV_CMD
, 2, ENC_LITTLE_ENDIAN
);
1153 proto_tree_add_item(icq_header_tree
, hf_icq_seqnum1
, tvb
, offset
+ ICQ5_SRV_SEQNUM1
, 2, ENC_LITTLE_ENDIAN
);
1154 proto_tree_add_item(icq_header_tree
, hf_icq_seqnum2
, tvb
, offset
+ ICQ5_SRV_SEQNUM2
, 2, ENC_LITTLE_ENDIAN
);
1155 proto_tree_add_item(icq_header_tree
, hf_icq_uin
, tvb
, offset
+ ICQ5_SRV_UIN
, 4, ENC_LITTLE_ENDIAN
);
1156 proto_tree_add_item(icq_header_tree
, hf_icq_checkcode
, tvb
, offset
+ ICQ5_SRV_CHECKCODE
, 4, ENC_LITTLE_ENDIAN
);
1158 icq_body_tree
= proto_tree_add_subtree(tree
, tvb
, ICQ5_CL_HDRSIZE
, pktsize
- ICQ5_SRV_HDRSIZE
, ett_icq_body
, NULL
, "Body");
1162 icqv5_srv_rand_user(icq_body_tree
, tvb
, offset
+ ICQ5_SRV_HDRSIZE
);
1164 case SRV_SYS_DELIVERED_MESS
:
1165 /* The message structures are all the same. Why not run
1166 * the same routine? */
1167 icqv5_cmd_send_msg(icq_body_tree
, tvb
, offset
+ ICQ5_SRV_HDRSIZE
,
1168 pktsize
- ICQ5_SRV_HDRSIZE
, pinfo
);
1170 case SRV_USER_ONLINE
:
1171 icqv5_srv_user_online(icq_body_tree
, tvb
, offset
+ ICQ5_SRV_HDRSIZE
);
1173 case SRV_USER_OFFLINE
:
1174 proto_tree_add_item(icq_body_tree
, hf_icq_uin
, tvb
, offset
+ ICQ5_SRV_HDRSIZE
+ SRV_USER_OFFLINE_UIN
, 4, ENC_LITTLE_ENDIAN
);
1176 case SRV_LOGIN_REPLY
:
1177 proto_tree_add_item(tree
, hf_icq_login_reply_ip
, tvb
, offset
+ ICQ5_SRV_HDRSIZE
+ SRV_LOGIN_REPLY_IP
, 4, ENC_BIG_ENDIAN
);
1180 icqv5_srv_meta_user(icq_body_tree
, tvb
, offset
+ ICQ5_SRV_HDRSIZE
,
1181 pktsize
- ICQ5_SRV_HDRSIZE
, pinfo
);
1183 case SRV_RECV_MESSAGE
:
1184 icqv5_srv_recv_message(icq_body_tree
, tvb
, offset
+ ICQ5_SRV_HDRSIZE
,
1185 pktsize
- ICQ5_SRV_HDRSIZE
, pinfo
);
1188 // We recurse here, but we'll run out of packet before we run out of stack.
1189 icqv5_srv_multi(icq_body_tree
, tvb
, offset
+ ICQ5_SRV_HDRSIZE
, pinfo
);
1192 case SRV_SILENT_TOO_LONG
:
1196 case SRV_UPDATE_SUCCESS
:
1197 proto_tree_add_item(icq_body_tree
, hf_icq_no_parameters
, tvb
, offset
+ ICQ5_SRV_HDRSIZE
, 0, ENC_NA
);
1200 expert_add_info(pinfo
, cmd_item
, &ei_icq_unknown_command
);
1205 static void dissect_icqv5(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
1207 if (tvb_get_letohl(tvb
, ICQ5_UNKNOWN
) == 0) {
1208 dissect_icqv5Client(tvb
, pinfo
, tree
);
1210 dissect_icqv5Server(tvb
, 0, pinfo
, tree
, -1);
1215 dissect_icq(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1219 proto_tree
*icq_tree
;
1221 version
= tvb_get_letohs(tvb
, ICQ_VERSION
);
1222 if (version
< 2 || version
> 5)
1223 return 0; /* This is not a (recognized) ICQ packet */
1225 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "ICQv%d", version
);
1226 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "ICQ Version %d protocol", version
);
1228 ti
= proto_tree_add_protocol_format(tree
, proto_icq
, tvb
, 0, -1, "ICQv%d", version
);
1229 icq_tree
= proto_item_add_subtree(ti
, ett_icq
);
1233 dissect_icqv5(tvb
, pinfo
, icq_tree
);
1237 proto_tree_add_item(icq_tree
, hf_icq_version
, tvb
, ICQ_VERSION
, 2, ENC_LITTLE_ENDIAN
);
1240 return (tvb_captured_length(tvb
));
1243 /* registration with the filtering engine */
1245 proto_register_icq(void)
1247 static hf_register_info hf
[] = {
1249 {"Version", "icq.version", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1251 {"Client/Server", "icq.client", FT_BOOLEAN
, BASE_NONE
, TFS(&tfs_client_server
), 0x0, NULL
, HFILL
}},
1253 {"Type", "icq.msg_type", FT_UINT16
, BASE_DEC
, VALS(msgTypeCode
), 0x0, NULL
, HFILL
}},
1255 {"UIN", "icq.uin", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1256 { &hf_icq_sessionid
,
1257 {"Session ID", "icq.sessionid", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1258 { &hf_icq_client_cmd
,
1259 {"Client command", "icq.client_cmd", FT_UINT16
, BASE_DEC
, VALS(clientCmdCode
), 0x0, NULL
, HFILL
}},
1260 { &hf_icq_server_cmd
,
1261 {"Server command", "icq.server_cmd", FT_UINT16
, BASE_DEC
, VALS(serverCmdCode
), 0x0, NULL
, HFILL
}},
1262 { &hf_icq_checkcode
,
1263 {"Checkcode", "icq.checkcode", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1264 { &hf_icq_checkcode_key
,
1265 {"Key", "icq.checkcode_key", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1267 {"Seq Number 1", "icq.seqnum1", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1269 {"Seq Number 2", "icq.seqnum2", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1271 {"Group", "icq.group", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1272 { &hf_icq_ack_random
,
1273 {"Random", "icq.ack.random", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1274 { &hf_icq_keep_alive_random
,
1275 {"Random", "icq.keep_alive.random", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1277 {"Client command", "icq.status", FT_UINT32
, BASE_DEC
, VALS(statusCode
), 0x0, NULL
, HFILL
}},
1278 { &hf_icq_meta_user_subcmd
,
1279 {"Subcommand", "icq.meta_user.subcmd", FT_UINT16
, BASE_DEC
, VALS(serverMetaSubCmdCode
), 0x0, NULL
, HFILL
}},
1280 /* Generated from convert_proto_tree_add_text.pl */
1281 { &hf_icq_msg_length
, { "Length", "icq.msg_length", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1282 { &hf_icq_msg
, { "Msg", "icq.msg", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1283 { &hf_icq_msg_authorization
, { "Authorization", "icq.msg_authorization", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1284 { &hf_icq_x1
, { "X1", "icq.x1", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1285 { &hf_icq_num_uin_pairs
, { "Number of pairs", "icq.num_uin_pairs", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1286 { &hf_icq_text_code_length
, { "Length", "icq.text_code_length", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1287 { &hf_icq_text_code
, { "Text", "icq.text_code", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1288 { &hf_icq_receiver_uin
, { "Receiver UIN", "icq.receiver_uin", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1289 { &hf_icq_login_time
, { "Time", "icq.login.time", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1290 { &hf_icq_login_port
, { "Port", "icq.login.port", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1291 { &hf_icq_login_password
, { "Password", "icq.login.password", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1292 { &hf_icq_login_ip
, { "IP", "icq.login.ip", FT_IPv4
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1293 { &hf_icq_number_of_uins
, { "Number of uins", "icq.number_of_uins", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1294 { &hf_icq_user_online_ip
, { "IP", "icq.user_online.ip", FT_IPv4
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1295 { &hf_icq_user_online_port
, { "Port", "icq.user_online.port", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1296 { &hf_icq_user_online_realip
, { "RealIP", "icq.user_online.realip", FT_IPv4
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1297 { &hf_icq_user_online_version
, { "Version", "icq.user_online.version", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1298 { &hf_icq_multi_num_packets
, { "Number of pkts", "icq.multi.num_packets", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1299 { &hf_icq_meta_user_result
, { "Result", "icq.meta_user.result", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1300 { &hf_icq_meta_user_length
, { "Length", "icq.meta_user.length", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1301 { &hf_icq_meta_user_found_authorization
, { "Authorization", "icq.meta_user.found_authorization", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1302 { &hf_icq_meta_user_x2
, { "x2", "icq.meta_user.x2", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1303 { &hf_icq_meta_user_x3
, { "x3", "icq.meta_user.x3", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1304 { &hf_icq_meta_user_about
, { "About", "icq.meta_user.about", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1305 { &hf_icq_meta_user_countrycode
, { "Countrycode", "icq.meta_user.countrycode", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1306 { &hf_icq_meta_user_timezone
, { "Timezone", "icq.meta_user.timezone", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1307 { &hf_icq_meta_user_info_authorization
, { "Authorization", "icq.meta_user.info_authorization", FT_BOOLEAN
, BASE_NONE
, TFS(&tfs_yes_no
), 0x0, NULL
, HFILL
}},
1308 { &hf_icq_meta_user_webaware
, { "Webaware", "icq.meta_user.webaware", FT_BOOLEAN
, BASE_NONE
, TFS(&tfs_yes_no
), 0x0, NULL
, HFILL
}},
1309 { &hf_icq_meta_user_hideip
, { "HideIP", "icq.meta_user.hideip", FT_BOOLEAN
, BASE_NONE
, TFS(&tfs_yes_no
), 0x0, NULL
, HFILL
}},
1310 { &hf_icq_rand_user_ip
, { "IP", "icq.rand_user.ip", FT_IPv4
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1311 { &hf_icq_rand_user_port
, { "Port", "icq.rand_user.port", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1312 { &hf_icq_rand_user_realip
, { "RealIP", "icq.rand_user.realip", FT_IPv4
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1313 { &hf_icq_rand_user_class
, { "Class", "icq.rand_user.class", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1314 { &hf_icq_rand_user_tcpversion
, { "TCPVersion", "icq.rand_user.tcpversion", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1315 { &hf_icq_no_parameters
, { "No parameters", "icq.no_parameters", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1316 { &hf_icq_login_reply_ip
, { "IP", "icq.login_reply.ip", FT_IPv4
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1317 { &hf_icq_nickname
, { "Nickname", "icq.nickname", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1318 { &hf_icq_first_name
, { "First name", "icq.first_name", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1319 { &hf_icq_last_name
, { "Last name", "icq.last_name", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1320 { &hf_icq_email
, { "Email", "icq.email", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1321 { &hf_icq_nickname_uint_string
, { "Nickname", "icq.nickname", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1322 { &hf_icq_first_name_uint_string
, { "First name", "icq.first_name", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1323 { &hf_icq_last_name_uint_string
, { "Last name", "icq.last_name", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1324 { &hf_icq_email_uint_string
, { "Email", "icq.email", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1325 { &hf_icq_primary_email
, { "Primary email", "icq.primary_email", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1326 { &hf_icq_secondary_email
, { "Secondary email", "icq.secondary_email", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1327 { &hf_icq_old_email
, { "Old email", "icq.old_email", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1328 { &hf_icq_city
, { "City", "icq.city", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1329 { &hf_icq_state
, { "State", "icq.state", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1330 { &hf_icq_phone
, { "Phone", "icq.phone", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1331 { &hf_icq_fax
, { "Fax", "icq.fax", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1332 { &hf_icq_street
, { "Street", "icq.street", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1333 { &hf_icq_cellphone
, { "Cellphone", "icq.cellphone", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1334 { &hf_icq_zip
, { "Zip", "icq.zip", FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1335 { &hf_icq_description
, { "Description", "icq.description", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1336 { &hf_icq_url
, { "URL", "icq.url", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1337 { &hf_icq_text
, { "Text", "icq.text", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1338 { &hf_icq_unknown
, { "Unknown", "icq.unknown", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1339 { &hf_icq_reason
, { "Reason", "icq.reason", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1340 { &hf_icq_msg_contact
, { "Contact", "icq.msg_contact", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1341 { &hf_icq_recv_time
, { "Time", "icq.recv_time", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1344 static int *ett
[] = {
1348 &ett_icq_body_parts
,
1350 static ei_register_info ei
[] = {
1351 { &ei_icq_unknown_meta_subcmd
, { "icq.unknown_meta_subcmd", PI_UNDECODED
, PI_WARN
, "Unknown meta subcmd", EXPFILL
}},
1352 { &ei_icq_unknown_command
, { "icq.unknown_command", PI_UNDECODED
, PI_WARN
, "Unknown command", EXPFILL
}},
1355 expert_module_t
*expert_icq
;
1357 proto_icq
= proto_register_protocol("ICQ Protocol", "ICQ", "icq");
1358 proto_register_field_array(proto_icq
, hf
, array_length(hf
));
1359 proto_register_subtree_array(ett
, array_length(ett
));
1360 expert_icq
= expert_register_protocol(proto_icq
);
1361 expert_register_field_array(expert_icq
, ei
, array_length(ei
));
1363 icq_handle
= register_dissector("icq", dissect_icq
, proto_icq
);
1367 proto_reg_handoff_icq(void)
1369 dissector_add_uint_with_preference("udp.port", UDP_PORT_ICQ
, icq_handle
);
1373 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1378 * indent-tabs-mode: nil
1381 * vi: set shiftwidth=4 tabstop=8 expandtab:
1382 * :indentSize=4:tabSize=8:noTabs=true: