HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-wow.c
blobdaeb225ec99e106ec83ababb3b7ac4815cb3ac26
1 /* packet-wow.c
2 * Routines for World of Warcraft (WoW) protocol dissection
3 * Copyright 2008-2009, Stephen Fisher (see AUTHORS file)
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
24 * USA.
27 /* This dissector is based on the MaNGOS project's source code, Stanford's
28 * SRP protocol documents (http://srp.stanford.edu) and RFC 2945: "The SRP
29 * Authentication and Key Exchange System." */
31 #include "config.h"
33 #include <glib.h>
35 #include <epan/packet.h>
36 #include <epan/prefs.h>
37 #include "packet-tcp.h"
39 typedef enum {
40 AUTH_LOGON_CHALLENGE = 0x00,
41 AUTH_LOGON_PROOF = 0x01,
42 REALM_LIST = 0x10,
43 XFER_INITIATE = 0x30,
44 XFER_DATA = 0x31,
45 XFER_ACCEPT = 0x32,
46 XFER_RESUME = 0x33,
47 XFER_CANCEL = 0x34
48 } auth_cmd_e;
50 static const value_string cmd_vs[] = {
51 { AUTH_LOGON_CHALLENGE, "Authentication Logon Challenge" },
52 { AUTH_LOGON_PROOF, "Authentication Logon Proof" },
53 { REALM_LIST, "Realm List" },
54 { XFER_INITIATE, "Transfer Initiate" },
55 { XFER_DATA, "Transfer Data" },
56 { XFER_ACCEPT, "Transfer Accept" },
57 { XFER_RESUME, "Transfer Resume" },
58 { XFER_CANCEL, "Transfer Cancel" },
59 { 0, NULL }
62 #if 0
63 static const value_string account_type_vs[] = {
64 { 0, "Player" },
65 { 1, "Moderator" },
66 { 2, "Game master" },
67 { 3, "Administrator" },
68 { 0, NULL }
70 #endif
72 static const value_string realm_status_vs[] = {
73 { 0, "Online" },
74 { 1, "Locked" },
75 { 2, "Offline" },
76 { 0, NULL }
79 static const value_string realm_type_vs[] = {
80 { 0, "Normal" },
81 { 1, "Player versus player" },
82 { 4, "Normal (2)" },
83 { 6, "Role playing normal" },
84 { 8, "Role playing player versus player)" },
85 { 0, NULL }
88 #define WOW_PORT 3724
90 #define WOW_CLIENT_TO_SERVER pinfo->destport == WOW_PORT
91 #define WOW_SERVER_TO_CLIENT pinfo->srcport == WOW_PORT
93 /* Initialize the protocol and registered fields */
94 static int proto_wow = -1;
96 static int hf_wow_command = -1;
97 static int hf_wow_error = -1;
98 static int hf_wow_pkt_size = -1;
99 static int hf_wow_gamename = -1;
100 static int hf_wow_version1 = -1;
101 static int hf_wow_version2 = -1;
102 static int hf_wow_version3 = -1;
103 static int hf_wow_build = -1;
104 static int hf_wow_platform = -1;
105 static int hf_wow_os = -1;
106 static int hf_wow_country = -1;
107 static int hf_wow_timezone_bias = -1;
108 static int hf_wow_ip = -1;
109 static int hf_wow_srp_i_len = -1;
110 static int hf_wow_srp_i = -1;
112 static int hf_wow_srp_b = -1;
113 static int hf_wow_srp_g_len = -1;
114 static int hf_wow_srp_g = -1;
115 static int hf_wow_srp_n_len = -1;
116 static int hf_wow_srp_n = -1;
117 static int hf_wow_srp_s = -1;
119 static int hf_wow_srp_a = -1;
120 static int hf_wow_srp_m1 = -1;
121 static int hf_wow_crc_hash = -1;
122 static int hf_wow_num_keys = -1;
124 static int hf_wow_srp_m2 = -1;
126 static int hf_wow_num_realms = -1;
127 static int hf_wow_realm_type = -1;
128 static int hf_wow_realm_status = -1;
129 static int hf_wow_realm_color = -1;
130 static int hf_wow_realm_name = -1;
131 static int hf_wow_realm_socket = -1;
132 static int hf_wow_realm_population_level = -1;
133 static int hf_wow_realm_num_characters = -1;
134 static int hf_wow_realm_timezone = -1;
136 static gboolean wow_preference_desegment = TRUE;
138 static gint ett_wow = -1;
139 static gint ett_wow_realms = -1;
141 static guint
142 get_wow_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
144 gint8 size_field_offset = -1;
145 guint8 cmd;
146 guint16 pkt_len;
148 cmd = tvb_get_guint8(tvb, offset);
150 if(WOW_SERVER_TO_CLIENT && cmd == REALM_LIST)
151 size_field_offset = 1;
152 if(WOW_CLIENT_TO_SERVER && cmd == AUTH_LOGON_CHALLENGE)
153 size_field_offset = 2;
155 pkt_len = tvb_get_letohs(tvb, size_field_offset);
157 return pkt_len + size_field_offset + 2;
161 static int
162 dissect_wow_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
164 proto_item *ti;
165 proto_tree *wow_tree, *wow_realms_tree;
167 gchar *string, *realm_name;
168 guint8 cmd, srp_i_len, srp_g_len, srp_n_len;
169 guint16 num_realms;
170 guint32 offset = 0;
171 gint len, ii;
173 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WOW");
175 col_clear(pinfo->cinfo, COL_INFO);
177 cmd = tvb_get_guint8(tvb, offset);
179 col_set_str(pinfo->cinfo, COL_INFO,
180 val_to_str_const(cmd, cmd_vs,
181 "Unrecognized packet type"));
183 if(tree) {
184 ti = proto_tree_add_item(tree, proto_wow, tvb, 0, -1, ENC_NA);
185 wow_tree = proto_item_add_subtree(ti, ett_wow);
187 proto_tree_add_item(wow_tree, hf_wow_command, tvb, offset, 1,
188 ENC_LITTLE_ENDIAN);
189 offset += 1;
191 switch(cmd) {
193 case AUTH_LOGON_CHALLENGE :
195 if(WOW_CLIENT_TO_SERVER) {
196 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
197 offset, 1, ENC_LITTLE_ENDIAN);
198 offset += 1;
200 proto_tree_add_item(wow_tree, hf_wow_pkt_size,
201 tvb, offset, 2, ENC_LITTLE_ENDIAN);
202 offset += 2;
204 string = g_strreverse(tvb_get_string(wmem_packet_scope(), tvb, offset, 4));
205 proto_tree_add_string(wow_tree, hf_wow_gamename,
206 tvb, offset, 4, string);
207 offset += 4;
209 proto_tree_add_item(wow_tree, hf_wow_version1,
210 tvb, offset, 1, ENC_LITTLE_ENDIAN);
211 offset += 1;
213 proto_tree_add_item(wow_tree, hf_wow_version2,
214 tvb, offset, 1, ENC_LITTLE_ENDIAN);
215 offset += 1;
217 proto_tree_add_item(wow_tree, hf_wow_version3,
218 tvb, offset, 1, ENC_LITTLE_ENDIAN);
219 offset += 1;
221 proto_tree_add_item(wow_tree, hf_wow_build, tvb,
222 offset, 2, ENC_LITTLE_ENDIAN);
223 offset += 2;
225 string = g_strreverse(tvb_get_string(wmem_packet_scope(), tvb, offset, 4));
226 proto_tree_add_string(wow_tree, hf_wow_platform,
227 tvb, offset, 4, string);
228 offset += 4;
230 string = g_strreverse(tvb_get_string(wmem_packet_scope(), tvb, offset, 4));
231 proto_tree_add_string(wow_tree, hf_wow_os, tvb,
232 offset, 4, string);
233 offset += 4;
235 string = g_strreverse(tvb_get_string(wmem_packet_scope(), tvb, offset, 4));
236 proto_tree_add_string(wow_tree, hf_wow_country,
237 tvb, offset, 4, string);
238 offset += 4;
240 proto_tree_add_item(wow_tree,
241 hf_wow_timezone_bias,
242 tvb, offset, 4, ENC_LITTLE_ENDIAN);
243 offset += 4;
245 proto_tree_add_item(wow_tree, hf_wow_ip, tvb,
246 offset, 4, ENC_BIG_ENDIAN);
247 offset += 4;
249 proto_tree_add_item(wow_tree,
250 hf_wow_srp_i_len,
251 tvb, offset, 1, ENC_LITTLE_ENDIAN);
252 srp_i_len = tvb_get_guint8(tvb, offset);
253 offset += 1;
255 proto_tree_add_item(wow_tree,
256 hf_wow_srp_i, tvb,
257 offset, srp_i_len,
258 ENC_ASCII|ENC_NA);
259 /*offset += srp_i_len;*/
262 } else if(WOW_SERVER_TO_CLIENT) {
263 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
264 offset, 1, ENC_LITTLE_ENDIAN);
265 offset += 1;
267 offset += 1; /* Unknown field */
269 proto_tree_add_item(wow_tree, hf_wow_srp_b, tvb,
270 offset, 32, ENC_NA);
271 offset += 32;
273 proto_tree_add_item(wow_tree, hf_wow_srp_g_len,
274 tvb, offset, 1, ENC_LITTLE_ENDIAN);
275 srp_g_len = tvb_get_guint8(tvb, offset);
276 offset += 1;
278 proto_tree_add_item(wow_tree, hf_wow_srp_g, tvb,
279 offset, srp_g_len, ENC_NA);
280 offset += srp_g_len;
282 proto_tree_add_item(wow_tree, hf_wow_srp_n_len,
283 tvb, offset, 1, ENC_LITTLE_ENDIAN);
284 srp_n_len = tvb_get_guint8(tvb, offset);
285 offset += 1;
287 proto_tree_add_item(wow_tree, hf_wow_srp_n, tvb,
288 offset, srp_n_len, ENC_NA);
289 offset += srp_n_len;
291 proto_tree_add_item(wow_tree, hf_wow_srp_s, tvb,
292 offset, 32, ENC_NA);
293 /*offset += 32;*/
295 /*offset += 16;*/ /* Unknown field */
298 break;
300 case AUTH_LOGON_PROOF :
302 if(WOW_CLIENT_TO_SERVER) {
303 proto_tree_add_item(wow_tree, hf_wow_srp_a, tvb,
304 offset, 32, ENC_NA);
305 offset += 32;
307 proto_tree_add_item(wow_tree, hf_wow_srp_m1,
308 tvb, offset, 20, ENC_NA);
309 offset += 20;
311 proto_tree_add_item(wow_tree, hf_wow_crc_hash,
312 tvb, offset, 20, ENC_NA);
313 offset += 20;
315 proto_tree_add_item(wow_tree, hf_wow_num_keys,
316 tvb, offset, 1, ENC_LITTLE_ENDIAN);
317 /*offset += 1;*/
319 /*offset += 1; *//* Unknown field */
321 } else if(WOW_SERVER_TO_CLIENT) {
322 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
323 offset, 1, ENC_LITTLE_ENDIAN);
324 offset += 1;
326 proto_tree_add_item(wow_tree, hf_wow_srp_m2,
327 tvb, offset, 20, ENC_NA);
328 /*offset += 20;*/
330 /*offset += 4;*/ /* Unknown field */
332 /*offset += 2;*/ /* Unknown field */
335 break;
337 case REALM_LIST :
339 if(WOW_CLIENT_TO_SERVER) {
342 } else if(WOW_SERVER_TO_CLIENT) {
344 proto_tree_add_item(wow_tree, hf_wow_pkt_size,
345 tvb, offset, 2, ENC_LITTLE_ENDIAN);
346 offset += 2;
348 offset += 4; /* Unknown field; always 0 */
350 proto_tree_add_item(wow_tree, hf_wow_num_realms,
351 tvb, offset, 2, ENC_LITTLE_ENDIAN);
352 num_realms = tvb_get_letohs(tvb, offset);
353 offset += 2;
355 for(ii = 0; ii < num_realms; ii++) {
356 realm_name = tvb_get_stringz(wmem_packet_scope(), tvb,
357 offset + 3,
358 &len);
360 ti = proto_tree_add_text(wow_tree, tvb,
361 offset, 0,
362 "%s",
363 realm_name);
365 wow_realms_tree = proto_item_add_subtree(ti, ett_wow_realms);
366 proto_tree_add_item(wow_realms_tree, hf_wow_realm_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
367 offset += 1;
369 proto_tree_add_item(wow_realms_tree, hf_wow_realm_status, tvb, offset, 1, ENC_LITTLE_ENDIAN);
370 offset += 1;
372 proto_tree_add_item(wow_realms_tree, hf_wow_realm_color, tvb, offset, 1, ENC_LITTLE_ENDIAN);
373 offset += 1;
375 proto_tree_add_string(wow_realms_tree, hf_wow_realm_name, tvb, offset, len, realm_name);
376 offset += len;
378 string = tvb_get_stringz(wmem_packet_scope(), tvb, offset,
379 &len);
380 proto_tree_add_string(wow_realms_tree, hf_wow_realm_socket, tvb, offset, len, string);
381 offset += len;
383 proto_tree_add_item(wow_realms_tree, hf_wow_realm_population_level, tvb, offset, 4, ENC_LITTLE_ENDIAN);
384 offset += 4;
386 proto_tree_add_item(wow_realms_tree, hf_wow_realm_num_characters, tvb, offset, 1, ENC_LITTLE_ENDIAN);
387 offset += 1;
389 proto_tree_add_item(wow_realms_tree, hf_wow_realm_timezone, tvb, offset, 1, ENC_LITTLE_ENDIAN);
390 offset += 1;
392 offset += 1; /* Unknown field */
395 break;
400 return tvb_length(tvb);
403 static gboolean
404 dissect_wow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
406 gint8 size_field_offset = -1;
407 guint8 cmd;
409 cmd = tvb_get_guint8(tvb, 0);
411 if(WOW_SERVER_TO_CLIENT && cmd == REALM_LIST)
412 size_field_offset = 1;
413 if(WOW_CLIENT_TO_SERVER && cmd == AUTH_LOGON_CHALLENGE)
414 size_field_offset = 2;
416 if(size_field_offset > -1) {
417 tcp_dissect_pdus(tvb, pinfo, tree, wow_preference_desegment,
418 size_field_offset+2, get_wow_pdu_len,
419 dissect_wow_pdu, data);
421 } else {
422 /* Doesn't have a size field, so it cannot span multiple
423 segments. Therefore, dissect this packet normally. */
424 dissect_wow_pdu(tvb, pinfo, tree, data);
427 return TRUE;
431 void
432 proto_register_wow(void)
434 module_t *wow_module; /* For our preferences */
436 static hf_register_info hf[] = {
437 { &hf_wow_command,
438 { "Command", "wow.cmd",
439 FT_UINT8, BASE_HEX, VALS(cmd_vs), 0,
440 "Type of packet", HFILL }
443 { &hf_wow_error,
444 { "Error", "wow.error",
445 FT_UINT8, BASE_DEC, 0, 0,
446 NULL, HFILL }
448 { &hf_wow_pkt_size,
449 { "Packet size", "wow.pkt_size",
450 FT_UINT16, BASE_DEC, 0, 0,
451 NULL, HFILL }
453 { &hf_wow_gamename,
454 { "Game name", "wow.gamename",
455 FT_STRING, BASE_NONE, 0, 0,
456 NULL, HFILL }
458 { &hf_wow_version1,
459 { "Version 1", "wow.version1",
460 FT_UINT8, BASE_DEC, 0, 0,
461 NULL, HFILL }
463 { &hf_wow_version2,
464 { "Version 2", "wow.version2",
465 FT_UINT8, BASE_DEC, 0, 0,
466 NULL, HFILL }
468 { &hf_wow_version3,
469 { "Version 3", "wow.version3",
470 FT_UINT8, BASE_DEC, 0, 0,
471 NULL, HFILL }
473 { &hf_wow_build,
474 { "Build", "wow.build",
475 FT_UINT16, BASE_DEC, 0, 0,
476 NULL, HFILL }
478 { &hf_wow_platform,
479 { "Platform", "wow.platform",
480 FT_STRING, BASE_NONE, 0, 0,
481 "CPU architecture of client system", HFILL }
483 { &hf_wow_os,
484 { "Operating system", "wow.os",
485 FT_STRING, BASE_NONE, 0, 0,
486 "Operating system of client system", HFILL }
488 { &hf_wow_country,
489 { "Country", "wow.country",
490 FT_STRING, BASE_NONE, 0, 0,
491 "Language and country of client system", HFILL }
493 { &hf_wow_timezone_bias,
494 { "Timezone bias", "wow.timezone_bias",
495 FT_UINT32, BASE_DEC, 0, 0,
496 NULL, HFILL }
498 { &hf_wow_ip,
499 { "IP address", "wow.ip",
500 FT_IPv4, BASE_NONE, 0, 0,
501 "Client's actual IP address", HFILL }
503 { &hf_wow_srp_i_len,
504 { "SRP I length", "wow.srp.i_len",
505 FT_UINT8, BASE_DEC, 0, 0,
506 "Secure Remote Password protocol 'I' value length", HFILL }
508 { &hf_wow_srp_i,
509 { "SRP I", "wow.srp.i",
510 FT_STRING, BASE_NONE, 0, 0,
511 "Secure Remote Password protocol 'I' value (username)", HFILL }
513 { &hf_wow_srp_b,
514 { "SRP B", "wow.srp.b",
515 FT_BYTES, BASE_NONE, 0, 0,
516 "Secure Remote Password protocol 'B' value (one of the public ephemeral values)", HFILL }
518 { &hf_wow_srp_g_len,
519 { "SRP g length", "wow.srp.g_len",
520 FT_UINT8, BASE_DEC, 0, 0,
521 "Secure Remote Password protocol 'g' value length",
522 HFILL }
524 { &hf_wow_srp_g,
525 { "SRP g", "wow.srp.g",
526 FT_BYTES, BASE_NONE, 0, 0,
527 "Secure Remote Password protocol 'g' value", HFILL }
529 { &hf_wow_srp_n_len,
530 { "SRP N length", "wow.srp.n_len",
531 FT_UINT8, BASE_DEC, 0, 0,
532 "Secure Remote Password protocol 'N' value length",
533 HFILL }
535 { &hf_wow_srp_n,
536 { "SRP N", "wow.srp.n",
537 FT_BYTES, BASE_NONE, 0, 0,
538 "Secure Remote Password protocol 'N' value (a large safe prime)", HFILL }
540 { &hf_wow_srp_s,
541 { "SRP s", "wow.srp.s",
542 FT_BYTES, BASE_NONE, 0, 0,
543 "Secure Remote Password protocol 's' (user's salt) value",
544 HFILL }
546 { &hf_wow_srp_a,
547 { "SRP A", "wow.srp.a",
548 FT_BYTES, BASE_NONE, 0, 0,
549 "Secure Remote Password protocol 'A' value (one of the public ephemeral values)", HFILL }
551 { &hf_wow_srp_m1,
552 { "SRP M1", "wow.srp.m1",
553 FT_BYTES, BASE_NONE, 0, 0,
554 "Secure Remote Password protocol 'M1' value", HFILL }
556 { &hf_wow_crc_hash,
557 { "CRC hash", "wow.crc_hash",
558 FT_BYTES, BASE_NONE, 0, 0,
559 NULL, HFILL }
561 { &hf_wow_num_keys,
562 { "Number of keys", "wow.num_keys",
563 FT_UINT8, BASE_DEC, 0, 0,
564 NULL, HFILL }
566 { &hf_wow_srp_m2,
567 { "SRP M2", "wow.srp.m2",
568 FT_BYTES, BASE_NONE, 0, 0,
569 "Secure Remote Password protocol 'M2' value", HFILL }
571 { &hf_wow_num_realms,
572 { "Number of realms", "wow.num_realms",
573 FT_UINT16, BASE_DEC, 0, 0,
574 NULL, HFILL }
576 { &hf_wow_realm_type,
577 { "Type", "wow.realm_type",
578 FT_UINT8, BASE_DEC, VALS(realm_type_vs), 0,
579 "Also known as realm icon", HFILL }
581 { &hf_wow_realm_status,
582 { "Status", "wow.realm_status",
583 FT_UINT8, BASE_DEC, VALS(realm_status_vs), 0,
584 NULL, HFILL }
586 { &hf_wow_realm_color,
587 { "Color", "wow.realm_color",
588 FT_UINT8, BASE_DEC, 0, 0,
589 NULL, HFILL }
591 { &hf_wow_realm_name,
592 { "Name", "wow.realm_name",
593 FT_STRINGZ, BASE_NONE, 0, 0,
594 NULL, HFILL }
596 { &hf_wow_realm_socket,
597 { "Server socket", "wow.realm_socket",
598 FT_STRINGZ, BASE_NONE, 0, 0,
599 "IP address and port to connect to on the server to reach this realm", HFILL }
601 { &hf_wow_realm_population_level,
602 { "Population level", "wow.realm_population_level",
603 FT_FLOAT, BASE_NONE, 0, 0,
604 NULL, HFILL }
606 { &hf_wow_realm_num_characters,
607 { "Number of characters", "wow.realm_num_characters",
608 FT_UINT8, BASE_DEC, 0, 0,
609 "Number of characters the user has in this realm", HFILL }
611 { &hf_wow_realm_timezone,
612 { "Timezone", "wow.realm_timezone",
613 FT_UINT8, BASE_DEC, 0, 0,
614 NULL, HFILL }
618 static gint *ett[] = {
619 &ett_wow,
620 &ett_wow_realms
623 proto_wow = proto_register_protocol("World of Warcraft",
624 "WOW", "wow");
626 proto_register_field_array(proto_wow, hf, array_length(hf));
627 proto_register_subtree_array(ett, array_length(ett));
629 wow_module = prefs_register_protocol(proto_wow, NULL);
631 prefs_register_bool_preference(wow_module, "desegment", "Reassemble wow messages spanning multiple TCP segments.", "Whether the wow dissector should reassemble messages spanning multiple TCP segments. To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", &wow_preference_desegment);
635 void
636 proto_reg_handoff_wow(void)
638 dissector_handle_t wow_handle;
640 wow_handle = new_create_dissector_handle(dissect_wow, proto_wow);
641 dissector_add_uint("tcp.port", WOW_PORT, wow_handle);