Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-icq.c
bloba55fcac1d6ab461a2f3f2b96358e5430ae3a56ed
1 /* packet-icq.c
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
9 */
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.
18 #include "config.h"
20 #include <epan/packet.h>
21 #include <epan/to_str.h>
22 #include <epan/expert.h>
23 #include <epan/tfs.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;
31 static int proto_icq;
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;
57 static int hf_icq_x1;
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;
111 static int ett_icq;
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
125 static void
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" },
228 { 0, NULL }
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" },
261 { 0, NULL }
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" },
346 { 0, NULL }
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" },
355 { STATUS_NA, "NA" },
356 { STATUS_CHAT, "Free for Chat" },
357 { 0, NULL }
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" },
393 { 0, NULL }
396 #if 0
397 static const value_string group_vals[] = {
398 { 1, "Name" },
399 { 2, "General" },
400 { 3, "Romance" },
401 { 4, "Games" },
402 { 5, "Students" },
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" },
409 { 0, NULL }
411 #endif
414 * All ICQv5 decryption code thanx to Sebastien Dault (daus01@gel.usherb.ca)
416 static const unsigned char
417 table_v5 [] = {
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 };
436 static uint32_t
437 get_v5key(uint32_t code, int len)
439 uint32_t a1, a2, a3, a4, a5;
440 uint32_t check, key;
442 a1 = code & 0x0001f000;
443 a2 = code & 0x07c007c0;
444 a3 = code & 0x003e0001;
445 a4 = code & 0xf8000000;
446 a5 = code & 0x0000083e;
448 a1 = a1 >> 0x0c;
449 a2 = a2 >> 0x01;
450 a3 = a3 << 0x0a;
451 a4 = a4 >> 0x10;
452 a5 = a5 << 0x0f;
454 check = a5 + a1 + a2 + a3 + a4;
455 key = len * 0x68656C6C;
456 key += check;
457 return key;
460 static void
461 decrypt_v5(unsigned char *bfr, uint32_t size,uint32_t key)
463 uint32_t i;
464 uint32_t k;
466 for (i=ICQ5_CL_SESSIONID; i < size; i+=4 ) {
467 k = key+table_v5[i&0xff];
468 if ( i != 0x16 ) {
469 bfr[i] ^= (unsigned char)(k & 0xff);
470 bfr[i+1] ^= (unsigned char)((k & 0xff00)>>8);
472 if ( i != 0x12 ) {
473 bfr[i+2] ^= (unsigned char)((k & 0xff0000)>>16);
474 bfr[i+3] ^= (unsigned char)((k & 0xff000000)>>24);
479 static void
480 icqv5_decode_msgType(proto_tree *tree, tvbuff_t *tvb, int offset, int size,
481 packet_info *pinfo)
483 proto_item *msg_item;
484 proto_tree *subtree;
485 int left = size;
486 uint16_t msgType;
487 int sep_offset;
488 int sz; /* Size of the current element */
489 unsigned int n;
490 static int * const url_field_descr[] = {
491 &hf_icq_description,
492 &hf_icq_url,
494 #define N_URL_FIELDS array_length(url_field_descr)
495 static int * const email_field_descr[] = {
496 &hf_icq_nickname,
497 &hf_icq_first_name,
498 &hf_icq_last_name,
499 &hf_icq_email,
500 &hf_icq_unknown,
501 &hf_icq_text,
503 #define N_EMAIL_FIELDS array_length(email_field_descr)
504 static int * const auth_req_field_descr[] = {
505 &hf_icq_nickname,
506 &hf_icq_first_name,
507 &hf_icq_last_name,
508 &hf_icq_email,
509 &hf_icq_unknown,
510 &hf_icq_reason,
512 #define N_AUTH_REQ_FIELDS array_length(auth_req_field_descr)
513 static int * const user_added_field_descr[] = {
514 &hf_icq_nickname,
515 &hf_icq_first_name,
516 &hf_icq_last_name,
517 &hf_icq_email,
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);
526 offset += 2;
527 left -= 2;
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);
534 offset += 2;
535 left -= 2;
538 switch(msgType) {
539 case 0xffff: /* Field unknown */
540 break;
541 default:
542 expert_add_info_format(pinfo, msg_item, &ei_icq_unknown_command,
543 "Unknown msgType: %u (0x%x)", msgType, msgType);
544 break;
545 case MSG_TEXT:
546 proto_tree_add_item(subtree, hf_icq_msg, tvb, offset, left, ENC_ASCII);
547 break;
548 case MSG_URL:
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;
553 } else {
554 sz = left;
556 if (sz != 0) {
557 proto_tree_add_item(subtree, *url_field_descr[n], tvb, offset, sz, ENC_ASCII|ENC_NA);
558 } else {
559 proto_tree_add_string_format_value(subtree, *url_field_descr[n], tvb, offset, 0,
560 "", "(empty)");
562 offset += sz;
563 left -= sz;
565 break;
566 case MSG_EMAIL:
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;
571 } else {
572 sz = left;
574 if (sz != 0) {
575 proto_tree_add_item(subtree, *email_field_descr[n], tvb, offset, sz, ENC_ASCII|ENC_NA);
576 } else {
577 proto_tree_add_string_format_value(subtree, *email_field_descr[n], tvb, offset, 0,
578 "", "(empty)");
580 offset += sz;
581 left -= sz;
583 break;
585 case MSG_AUTH:
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");
594 offset++;
595 proto_tree_add_item(subtree, hf_icq_x1, tvb, offset, 2, ENC_LITTLE_ENDIAN);
596 break;
598 case MSG_AUTH_REQ:
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;
603 } else {
604 sz = left;
606 if (sz != 0) {
607 proto_tree_add_item(subtree, *auth_req_field_descr[n], tvb, offset, sz, ENC_ASCII|ENC_NA);
608 } else {
609 proto_tree_add_string_format_value(subtree, *auth_req_field_descr[n], tvb, offset, 0,
610 "", "(empty)");
612 offset += sz;
613 left -= sz;
615 break;
616 case MSG_USER_ADDED:
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;
621 } else {
622 sz = left;
624 if (sz != 0) {
625 proto_tree_add_item(subtree, *user_added_field_descr[n], tvb, offset, sz, ENC_ASCII|ENC_NA);
626 } else {
627 proto_tree_add_string_format_value(subtree, *user_added_field_descr[n], tvb, offset, 0,
628 "", "(empty)");
630 offset += sz;
631 left -= sz;
633 break;
634 case MSG_CONTACTS:
636 int sep_offset_prev;
637 int sz_local = 0; /* Size of the current element */
638 int n_local = 0; /* The nth element */
639 bool last = false;
641 while (!last) {
642 sep_offset = tvb_find_uint8(tvb, offset, left, 0xfe);
643 if (sep_offset != -1) {
644 sz_local = sep_offset - offset + 1;
646 else {
647 sz_local = left;
648 last = true;
651 if (n_local == 0) {
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);
654 n_local++;
655 } else if (!last) {
656 int svsz = sz_local;
657 char* contact;
659 left -= sz_local;
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;
664 else {
665 sz_local = left;
666 last = true;
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,
670 contact, "%s: %s",
671 tvb_get_string_enc(pinfo->pool, tvb, offset, svsz, ENC_ASCII),
672 contact);
673 n_local += 2;
676 left -= (sz_local+1);
677 offset = sep_offset + 1;
679 break;
684 /*********************************
686 * Client commands
688 *********************************/
689 static void
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;
695 uint16_t len;
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);
700 if (len>0) {
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);
707 static void
708 icqv5_cmd_send_msg(proto_tree *tree, tvbuff_t *tvb, int offset, int size,
709 packet_info *pinfo)
711 proto_tree_add_item(tree, hf_icq_receiver_uin, tvb, offset + CMD_SEND_MSG_RECV_UIN, 4, ENC_LITTLE_ENDIAN);
712 size -= 4;
714 icqv5_decode_msgType(tree, tvb, offset + CMD_SEND_MSG_MSG_TYPE,
715 size, pinfo);
718 static void
719 icqv5_cmd_login(proto_tree *tree, tvbuff_t *tvb, int offset, packet_info *pinfo)
721 proto_tree *subtree = tree;
722 time_t theTime;
723 char *aTime;
724 uint32_t passwdLen;
726 if (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);
739 static void
740 icqv5_cmd_contact_list(proto_tree *tree, tvbuff_t *tvb, int offset)
742 unsigned char num;
743 int i;
744 uint32_t uin;
746 if (tree) {
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);
757 offset += 4;
762 /**********************
764 * Server commands
766 **********************
768 static void
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;
775 if (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);
790 static void
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 */
795 packet_info *pinfo)
797 uint8_t num;
798 uint16_t pktSz;
799 int i;
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);
809 offset += 2;
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);
812 offset += pktSz;
816 static void
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 */
821 packet_info *pinfo)
823 proto_tree *sstree;
824 proto_item *ti;
825 uint16_t subcmd;
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 */
836 offset += 3;
838 switch(subcmd) {
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);
848 offset += 2;
850 /* FALLTHRU */
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
858 int len = 0;
859 unsigned char auth;
861 * Read UIN
863 proto_tree_add_item(sstree, hf_icq_uin, tvb, offset, 4, ENC_LITTLE_ENDIAN);
864 offset+=4;
866 proto_tree_add_item_ret_length(sstree, hf_icq_nickname_uint_string, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
867 offset += len;
868 proto_tree_add_item_ret_length(sstree, hf_icq_first_name_uint_string, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
869 offset += len;
870 proto_tree_add_item_ret_length(sstree, hf_icq_last_name_uint_string, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
871 offset += len;
872 proto_tree_add_item_ret_length(sstree, hf_icq_email_uint_string, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
873 offset += 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");
879 offset++;
880 /* Get x2 */
881 proto_tree_add_item(sstree, hf_icq_meta_user_x2, tvb, offset, 2, ENC_LITTLE_ENDIAN);
882 offset+=2;
883 /* Get x3 */
884 proto_tree_add_item(sstree, hf_icq_meta_user_x3, tvb, offset, 4, ENC_LITTLE_ENDIAN);
885 break;
887 case META_ABOUT:
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);
892 break;
894 case META_USER_INFO:
896 int len = 0;
897 #if 0
898 /* Get the uin */
899 proto_tree_add_item(sstree, hf_icq_uin, tvb, offset, 4, ENC_LITTLE_ENDIAN);
900 offset+=4;
901 #endif
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);
907 offset+=len;
908 proto_tree_add_item_ret_length(sstree, hf_icq_first_name_uint_string, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
909 offset+=len;
910 proto_tree_add_item_ret_length(sstree, hf_icq_last_name_uint_string, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
911 offset+=len;
912 proto_tree_add_item_ret_length(sstree, hf_icq_primary_email, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
913 offset+=len;
914 proto_tree_add_item_ret_length(sstree, hf_icq_secondary_email, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
915 offset+=len;
916 proto_tree_add_item_ret_length(sstree, hf_icq_old_email, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
917 offset+=len;
918 proto_tree_add_item_ret_length(sstree, hf_icq_city, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
919 offset+=len;
920 proto_tree_add_item_ret_length(sstree, hf_icq_state, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
921 offset+=len;
922 proto_tree_add_item_ret_length(sstree, hf_icq_phone, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
923 offset+=len;
924 proto_tree_add_item_ret_length(sstree, hf_icq_fax, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
925 offset+=len;
926 proto_tree_add_item_ret_length(sstree, hf_icq_street, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
927 offset+=len;
928 proto_tree_add_item_ret_length(sstree, hf_icq_cellphone, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
929 offset+=len;
930 proto_tree_add_item_ret_length(sstree, hf_icq_zip, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_ASCII, &len);
931 offset+=len;
933 /* Get country code */
934 proto_tree_add_item(sstree, hf_icq_meta_user_countrycode, tvb, offset, 2, ENC_LITTLE_ENDIAN);
935 offset+=2;
936 /* Get the timezone setting */
937 proto_tree_add_item(sstree, hf_icq_meta_user_timezone, tvb, offset, 1, ENC_NA);
938 offset++;
939 /* Get the authorize setting */
940 proto_tree_add_item(sstree, hf_icq_meta_user_info_authorization, tvb, offset, 1, ENC_NA);
941 offset++;
942 /* Get the webaware setting */
943 proto_tree_add_item(sstree, hf_icq_meta_user_webaware, tvb, offset, 1, ENC_NA);
944 offset++;
945 /* Get the authorize setting */
946 proto_tree_add_item(sstree, hf_icq_meta_user_hideip, tvb, offset, 1, ENC_NA);
947 break;
949 default:
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);
953 break;
957 static void
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 */
962 packet_info *pinfo)
964 uint16_t year;
965 uint8_t month;
966 uint8_t day;
967 uint8_t hour;
968 uint8_t minute;
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,
982 size-10, pinfo);
985 static void
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;
991 uint8_t commClass;
993 if (tree) {
994 /* uint32_t UIN */
995 proto_tree_add_item(subtree, hf_icq_uin, tvb, offset + SRV_RAND_USER_UIN,
996 4, ENC_LITTLE_ENDIAN);
997 /* uint32_t IP */
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.
1020 static void
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;
1029 uint32_t code, key;
1030 uint16_t cmd;
1031 uint8_t *decr_pd; /* Decrypted content */
1032 tvbuff_t *decr_tvb;
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");
1084 switch(cmd) {
1085 case CMD_ACK:
1086 proto_tree_add_item(icq_body_tree, hf_icq_ack_random, decr_tvb, ICQ5_CL_HDRSIZE + CMD_ACK_RANDOM, 4, ENC_LITTLE_ENDIAN);
1087 break;
1088 case CMD_SEND_MSG:
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);
1092 break;
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);
1095 break;
1096 case CMD_LOGIN:
1097 icqv5_cmd_login(icq_body_tree, decr_tvb, ICQ5_CL_HDRSIZE, pinfo);
1098 break;
1099 case CMD_SEND_TEXT_CODE:
1100 icqv5_cmd_send_text_code(icq_body_tree, decr_tvb, ICQ5_CL_HDRSIZE);
1101 break;
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);
1104 break;
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);
1107 break;
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);
1110 break;
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);
1113 break;
1114 case CMD_CONTACT_LIST:
1115 icqv5_cmd_contact_list(icq_body_tree, decr_tvb, ICQ5_CL_HDRSIZE);
1116 break;
1117 case CMD_META_USER:
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);
1122 break;
1123 default:
1124 expert_add_info(pinfo, cmd_item, &ei_icq_unknown_command);
1125 break;
1129 static void
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");
1160 switch (cmd) {
1161 case SRV_RAND_USER:
1162 icqv5_srv_rand_user(icq_body_tree, tvb, offset + ICQ5_SRV_HDRSIZE);
1163 break;
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);
1169 break;
1170 case SRV_USER_ONLINE:
1171 icqv5_srv_user_online(icq_body_tree, tvb, offset + ICQ5_SRV_HDRSIZE);
1172 break;
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);
1175 break;
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);
1178 break;
1179 case SRV_META_USER:
1180 icqv5_srv_meta_user(icq_body_tree, tvb, offset + ICQ5_SRV_HDRSIZE,
1181 pktsize - ICQ5_SRV_HDRSIZE, pinfo);
1182 break;
1183 case SRV_RECV_MESSAGE:
1184 icqv5_srv_recv_message(icq_body_tree, tvb, offset + ICQ5_SRV_HDRSIZE,
1185 pktsize - ICQ5_SRV_HDRSIZE, pinfo);
1186 break;
1187 case SRV_MULTI:
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);
1190 break;
1191 case SRV_ACK:
1192 case SRV_SILENT_TOO_LONG:
1193 case SRV_GO_AWAY:
1194 case SRV_NEW_UIN:
1195 case SRV_BAD_PASS:
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);
1198 break;
1199 default:
1200 expert_add_info(pinfo, cmd_item, &ei_icq_unknown_command);
1201 break;
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);
1209 } else {
1210 dissect_icqv5Server(tvb, 0, pinfo, tree, -1);
1214 static int
1215 dissect_icq(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1217 int version;
1218 proto_item *ti;
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);
1231 if (version == 5)
1233 dissect_icqv5(tvb, pinfo, icq_tree);
1235 else
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 */
1244 void
1245 proto_register_icq(void)
1247 static hf_register_info hf[] = {
1248 { &hf_icq_version,
1249 {"Version", "icq.version", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1250 { &hf_icq_type,
1251 {"Client/Server", "icq.client", FT_BOOLEAN, BASE_NONE, TFS(&tfs_client_server), 0x0, NULL, HFILL }},
1252 { &hf_icq_msg_type,
1253 {"Type", "icq.msg_type", FT_UINT16, BASE_DEC, VALS(msgTypeCode), 0x0, NULL, HFILL }},
1254 { &hf_icq_uin,
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 }},
1266 { &hf_icq_seqnum1,
1267 {"Seq Number 1", "icq.seqnum1", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1268 { &hf_icq_seqnum2,
1269 {"Seq Number 2", "icq.seqnum2", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1270 { &hf_icq_group,
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 }},
1276 { &hf_icq_status,
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[] = {
1345 &ett_icq,
1346 &ett_icq_header,
1347 &ett_icq_body,
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);
1366 void
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
1375 * Local variables:
1376 * c-basic-offset: 4
1377 * tab-width: 8
1378 * indent-tabs-mode: nil
1379 * End:
1381 * vi: set shiftwidth=4 tabstop=8 expandtab:
1382 * :indentSize=4:tabSize=8:noTabs=true: