2 * Routines for World of Warcraft (WoW) protocol dissection
3 * Copyright 2008-2009, Stephen Fisher (see AUTHORS file)
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,
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." */
35 #include <epan/packet.h>
36 #include <epan/prefs.h>
37 #include "packet-tcp.h"
40 AUTH_LOGON_CHALLENGE = 0x00,
41 AUTH_LOGON_PROOF = 0x01,
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" },
62 static const value_string account_type_vs[] = {
66 { 3, "Administrator" },
70 static const value_string realm_status_vs[] = {
77 static const value_string realm_type_vs[] = {
79 { 1, "Player versus player" },
81 { 6, "Role playing normal" },
82 { 8, "Role playing player versus player)" },
88 #define WOW_CLIENT_TO_SERVER pinfo->destport == WOW_PORT
89 #define WOW_SERVER_TO_CLIENT pinfo->srcport == WOW_PORT
91 /* Initialize the protocol and registered fields */
92 static int proto_wow = -1;
94 static int hf_wow_command = -1;
95 static int hf_wow_error = -1;
96 static int hf_wow_pkt_size = -1;
97 static int hf_wow_gamename = -1;
98 static int hf_wow_version1 = -1;
99 static int hf_wow_version2 = -1;
100 static int hf_wow_version3 = -1;
101 static int hf_wow_build = -1;
102 static int hf_wow_platform = -1;
103 static int hf_wow_os = -1;
104 static int hf_wow_country = -1;
105 static int hf_wow_timezone_bias = -1;
106 static int hf_wow_ip = -1;
107 static int hf_wow_srp_i_len = -1;
108 static int hf_wow_srp_i = -1;
110 static int hf_wow_srp_b = -1;
111 static int hf_wow_srp_g_len = -1;
112 static int hf_wow_srp_g = -1;
113 static int hf_wow_srp_n_len = -1;
114 static int hf_wow_srp_n = -1;
115 static int hf_wow_srp_s = -1;
117 static int hf_wow_srp_a = -1;
118 static int hf_wow_srp_m1 = -1;
119 static int hf_wow_crc_hash = -1;
120 static int hf_wow_num_keys = -1;
122 static int hf_wow_srp_m2 = -1;
124 static int hf_wow_num_realms = -1;
125 static int hf_wow_realm_type = -1;
126 static int hf_wow_realm_status = -1;
127 static int hf_wow_realm_color = -1;
128 static int hf_wow_realm_name = -1;
129 static int hf_wow_realm_socket = -1;
130 static int hf_wow_realm_population_level = -1;
131 static int hf_wow_realm_num_characters = -1;
132 static int hf_wow_realm_timezone = -1;
134 static gboolean wow_preference_desegment = TRUE;
136 static gint ett_wow = -1;
137 static gint ett_wow_realms = -1;
139 static void dissect_wow_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
140 static guint get_wow_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset);
144 dissect_wow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
146 gint8 size_field_offset = -1;
149 cmd = tvb_get_guint8(tvb, 0);
151 if(WOW_SERVER_TO_CLIENT && cmd == REALM_LIST)
152 size_field_offset = 1;
153 if(WOW_CLIENT_TO_SERVER && cmd == AUTH_LOGON_CHALLENGE)
154 size_field_offset = 2;
156 if(size_field_offset > -1) {
157 tcp_dissect_pdus(tvb, pinfo, tree, wow_preference_desegment,
158 size_field_offset+2, get_wow_pdu_len,
162 /* Doesn't have a size field, so it cannot span multiple
163 segments. Therefore, dissect this packet normally. */
164 dissect_wow_pdu(tvb, pinfo, tree);
171 get_wow_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
173 gint8 size_field_offset = -1;
177 cmd = tvb_get_guint8(tvb, offset);
179 if(WOW_SERVER_TO_CLIENT && cmd == REALM_LIST)
180 size_field_offset = 1;
181 if(WOW_CLIENT_TO_SERVER && cmd == AUTH_LOGON_CHALLENGE)
182 size_field_offset = 2;
184 pkt_len = tvb_get_letohs(tvb, size_field_offset);
186 return pkt_len + size_field_offset + 2;
191 dissect_wow_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
194 proto_tree *wow_tree, *wow_realms_tree;
196 gchar *string, *realm_name;
197 guint8 cmd, srp_i_len, srp_g_len, srp_n_len;
202 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WOW");
204 col_clear(pinfo->cinfo, COL_INFO);
206 cmd = tvb_get_guint8(tvb, offset);
208 if(check_col(pinfo->cinfo, COL_INFO)) {
209 col_set_str(pinfo->cinfo, COL_INFO,
210 val_to_str_const(cmd, cmd_vs,
211 "Unrecognized packet type"));
215 ti = proto_tree_add_item(tree, proto_wow, tvb, 0, -1, ENC_NA);
216 wow_tree = proto_item_add_subtree(ti, ett_wow);
218 proto_tree_add_item(wow_tree, hf_wow_command, tvb, offset, 1,
224 case AUTH_LOGON_CHALLENGE :
226 if(WOW_CLIENT_TO_SERVER) {
227 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
228 offset, 1, ENC_LITTLE_ENDIAN);
231 proto_tree_add_item(wow_tree, hf_wow_pkt_size,
232 tvb, offset, 2, ENC_LITTLE_ENDIAN);
235 string = g_strreverse(tvb_get_ephemeral_string(tvb, offset, 4));
236 proto_tree_add_string(wow_tree, hf_wow_gamename,
237 tvb, offset, 4, string);
240 proto_tree_add_item(wow_tree, hf_wow_version1,
241 tvb, offset, 1, ENC_LITTLE_ENDIAN);
244 proto_tree_add_item(wow_tree, hf_wow_version2,
245 tvb, offset, 1, ENC_LITTLE_ENDIAN);
248 proto_tree_add_item(wow_tree, hf_wow_version3,
249 tvb, offset, 1, ENC_LITTLE_ENDIAN);
252 proto_tree_add_item(wow_tree, hf_wow_build, tvb,
253 offset, 2, ENC_LITTLE_ENDIAN);
256 string = g_strreverse(tvb_get_ephemeral_string(tvb, offset, 4));
257 proto_tree_add_string(wow_tree, hf_wow_platform,
258 tvb, offset, 4, string);
261 string = g_strreverse(tvb_get_ephemeral_string(tvb, offset, 4));
262 proto_tree_add_string(wow_tree, hf_wow_os, tvb,
266 string = g_strreverse(tvb_get_ephemeral_string(tvb, offset, 4));
267 proto_tree_add_string(wow_tree, hf_wow_country,
268 tvb, offset, 4, string);
271 proto_tree_add_item(wow_tree,
272 hf_wow_timezone_bias,
273 tvb, offset, 4, ENC_LITTLE_ENDIAN);
276 proto_tree_add_item(wow_tree, hf_wow_ip, tvb,
277 offset, 4, ENC_BIG_ENDIAN);
280 proto_tree_add_item(wow_tree,
282 tvb, offset, 1, ENC_LITTLE_ENDIAN);
283 srp_i_len = tvb_get_guint8(tvb, offset);
286 proto_tree_add_item(wow_tree,
293 } else if(WOW_SERVER_TO_CLIENT) {
294 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
295 offset, 1, ENC_LITTLE_ENDIAN);
298 offset += 1; /* Unknown field */
300 proto_tree_add_item(wow_tree, hf_wow_srp_b, tvb,
304 proto_tree_add_item(wow_tree, hf_wow_srp_g_len,
305 tvb, offset, 1, ENC_LITTLE_ENDIAN);
306 srp_g_len = tvb_get_guint8(tvb, offset);
309 proto_tree_add_item(wow_tree, hf_wow_srp_g, tvb,
310 offset, srp_g_len, ENC_NA);
313 proto_tree_add_item(wow_tree, hf_wow_srp_n_len,
314 tvb, offset, 1, ENC_LITTLE_ENDIAN);
315 srp_n_len = tvb_get_guint8(tvb, offset);
318 proto_tree_add_item(wow_tree, hf_wow_srp_n, tvb,
319 offset, srp_n_len, ENC_NA);
322 proto_tree_add_item(wow_tree, hf_wow_srp_s, tvb,
326 offset += 16; /* Unknown field */
331 case AUTH_LOGON_PROOF :
333 if(WOW_CLIENT_TO_SERVER) {
334 proto_tree_add_item(wow_tree, hf_wow_srp_a, tvb,
338 proto_tree_add_item(wow_tree, hf_wow_srp_m1,
339 tvb, offset, 20, ENC_NA);
342 proto_tree_add_item(wow_tree, hf_wow_crc_hash,
343 tvb, offset, 20, ENC_NA);
346 proto_tree_add_item(wow_tree, hf_wow_num_keys,
347 tvb, offset, 1, ENC_LITTLE_ENDIAN);
350 offset += 1; /* Unknown field */
352 } else if(WOW_SERVER_TO_CLIENT) {
353 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
354 offset, 1, ENC_LITTLE_ENDIAN);
357 proto_tree_add_item(wow_tree, hf_wow_srp_m2,
358 tvb, offset, 20, ENC_NA);
361 offset += 4; /* Unknown field */
363 offset += 2; /* Unknown field */
370 if(WOW_CLIENT_TO_SERVER) {
373 } else if(WOW_SERVER_TO_CLIENT) {
375 proto_tree_add_item(wow_tree, hf_wow_pkt_size,
376 tvb, offset, 2, ENC_LITTLE_ENDIAN);
379 offset += 4; /* Unknown field; always 0 */
381 proto_tree_add_item(wow_tree, hf_wow_num_realms,
382 tvb, offset, 2, ENC_LITTLE_ENDIAN);
383 num_realms = tvb_get_letohs(tvb, offset);
386 for(i = 1; i <= num_realms; i++) {
387 realm_name = tvb_get_ephemeral_stringz(tvb,
391 ti = proto_tree_add_text(wow_tree, tvb,
396 wow_realms_tree = proto_item_add_subtree(ti, ett_wow_realms);
397 proto_tree_add_item(wow_realms_tree, hf_wow_realm_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
400 proto_tree_add_item(wow_realms_tree, hf_wow_realm_status, tvb, offset, 1, ENC_LITTLE_ENDIAN);
403 proto_tree_add_item(wow_realms_tree, hf_wow_realm_color, tvb, offset, 1, ENC_LITTLE_ENDIAN);
406 proto_tree_add_string(wow_realms_tree, hf_wow_realm_name, tvb, offset, len, realm_name);
409 string = tvb_get_ephemeral_stringz(tvb, offset,
411 proto_tree_add_string(wow_realms_tree, hf_wow_realm_socket, tvb, offset, len, string);
414 proto_tree_add_item(wow_realms_tree, hf_wow_realm_population_level, tvb, offset, 4, ENC_LITTLE_ENDIAN);
417 proto_tree_add_item(wow_realms_tree, hf_wow_realm_num_characters, tvb, offset, 1, ENC_LITTLE_ENDIAN);
420 proto_tree_add_item(wow_realms_tree, hf_wow_realm_timezone, tvb, offset, 1, ENC_LITTLE_ENDIAN);
423 offset += 1; /* Unknown field */
434 proto_register_wow(void)
436 module_t *wow_module; /* For our preferences */
438 static hf_register_info hf[] = {
440 { "Command", "wow.cmd",
441 FT_UINT8, BASE_HEX, VALS(cmd_vs), 0,
442 "Type of packet", HFILL }
446 { "Error", "wow.error",
447 FT_UINT8, BASE_DEC, 0, 0,
451 { "Packet size", "wow.pkt_size",
452 FT_UINT16, BASE_DEC, 0, 0,
456 { "Game name", "wow.gamename",
457 FT_STRING, BASE_NONE, 0, 0,
461 { "Version 1", "wow.version1",
462 FT_UINT8, BASE_DEC, 0, 0,
466 { "Version 2", "wow.version2",
467 FT_UINT8, BASE_DEC, 0, 0,
471 { "Version 3", "wow.version3",
472 FT_UINT8, BASE_DEC, 0, 0,
476 { "Build", "wow.build",
477 FT_UINT16, BASE_DEC, 0, 0,
481 { "Platform", "wow.platform",
482 FT_STRING, BASE_NONE, 0, 0,
483 "CPU architecture of client system", HFILL }
486 { "Operating system", "wow.os",
487 FT_STRING, BASE_NONE, 0, 0,
488 "Operating system of client system", HFILL }
491 { "Country", "wow.country",
492 FT_STRING, BASE_NONE, 0, 0,
493 "Language and country of client system", HFILL }
495 { &hf_wow_timezone_bias,
496 { "Timezone bias", "wow.timezone_bias",
497 FT_UINT32, BASE_DEC, 0, 0,
501 { "IP address", "wow.ip",
502 FT_IPv4, BASE_NONE, 0, 0,
503 "Client's actual IP address", HFILL }
506 { "SRP I length", "wow.srp.i_len",
507 FT_UINT8, BASE_DEC, 0, 0,
508 "Secure Remote Password protocol 'I' value length", HFILL }
511 { "SRP I", "wow.srp.i",
512 FT_STRING, BASE_NONE, 0, 0,
513 "Secure Remote Password protocol 'I' value (username)", HFILL }
516 { "SRP B", "wow.srp.b",
517 FT_BYTES, BASE_NONE, 0, 0,
518 "Secure Remote Password protocol 'B' value (one of the public ephemeral values)", HFILL }
521 { "SRP g length", "wow.srp.g_len",
522 FT_UINT8, BASE_DEC, 0, 0,
523 "Secure Remote Password protocol 'g' value length",
527 { "SRP g", "wow.srp.g",
528 FT_BYTES, BASE_NONE, 0, 0,
529 "Secure Remote Password protocol 'g' value", HFILL }
532 { "SRP N length", "wow.srp.n_len",
533 FT_UINT8, BASE_DEC, 0, 0,
534 "Secure Remote Password protocol 'N' value length",
538 { "SRP N", "wow.srp.n",
539 FT_BYTES, BASE_NONE, 0, 0,
540 "Secure Remote Password protocol 'N' value (a large safe prime)", HFILL }
543 { "SRP s", "wow.srp.s",
544 FT_BYTES, BASE_NONE, 0, 0,
545 "Secure Remote Password protocol 's' (user's salt) value",
549 { "SRP A", "wow.srp.a",
550 FT_BYTES, BASE_NONE, 0, 0,
551 "Secure Remote Password protocol 'A' value (one of the public ephemeral values)", HFILL }
554 { "SRP M1", "wow.srp.m1",
555 FT_BYTES, BASE_NONE, 0, 0,
556 "Secure Remote Password protocol 'M1' value", HFILL }
559 { "CRC hash", "wow.crc_hash",
560 FT_BYTES, BASE_NONE, 0, 0,
564 { "Number of keys", "wow.num_keys",
565 FT_UINT8, BASE_DEC, 0, 0,
569 { "SRP M2", "wow.srp.m2",
570 FT_BYTES, BASE_NONE, 0, 0,
571 "Secure Remote Password protocol 'M2' value", HFILL }
573 { &hf_wow_num_realms,
574 { "Number of realms", "wow.num_realms",
575 FT_UINT16, BASE_DEC, 0, 0,
578 { &hf_wow_realm_type,
579 { "Type", "wow.realm_type",
580 FT_UINT8, BASE_DEC, VALS(realm_type_vs), 0,
581 "Also known as realm icon", HFILL }
583 { &hf_wow_realm_status,
584 { "Status", "wow.realm_status",
585 FT_UINT8, BASE_DEC, VALS(realm_status_vs), 0,
588 { &hf_wow_realm_color,
589 { "Color", "wow.realm_color",
590 FT_UINT8, BASE_DEC, 0, 0,
593 { &hf_wow_realm_name,
594 { "Name", "wow.realm_name",
595 FT_STRINGZ, BASE_NONE, 0, 0,
598 { &hf_wow_realm_socket,
599 { "Server socket", "wow.realm_socket",
600 FT_STRINGZ, BASE_NONE, 0, 0,
601 "IP address and port to connect to on the server to reach this realm", HFILL }
603 { &hf_wow_realm_population_level,
604 { "Population level", "wow.realm_population_level",
605 FT_FLOAT, BASE_NONE, 0, 0,
608 { &hf_wow_realm_num_characters,
609 { "Number of characters", "wow.realm_num_characters",
610 FT_UINT8, BASE_DEC, 0, 0,
611 "Number of characters the user has in this realm", HFILL }
613 { &hf_wow_realm_timezone,
614 { "Timezone", "wow.realm_timezone",
615 FT_UINT8, BASE_DEC, 0, 0,
620 static gint *ett[] = {
625 proto_wow = proto_register_protocol("World of Warcraft",
628 proto_register_field_array(proto_wow, hf, array_length(hf));
629 proto_register_subtree_array(ett, array_length(ett));
631 wow_module = prefs_register_protocol(proto_wow, NULL);
633 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);
638 proto_reg_handoff_wow(void)
640 dissector_handle_t wow_handle;
642 wow_handle = new_create_dissector_handle(dissect_wow, proto_wow);
643 dissector_add_uint("tcp.port", WOW_PORT, wow_handle);