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." */
39 #include <epan/packet.h>
40 #include <epan/prefs.h>
41 #include "packet-tcp.h"
44 AUTH_LOGON_CHALLENGE = 0x00,
45 AUTH_LOGON_PROOF = 0x01,
54 static const value_string cmd_vs[] = {
55 { AUTH_LOGON_CHALLENGE, "Authentication Logon Challenge" },
56 { AUTH_LOGON_PROOF, "Authentication Logon Proof" },
57 { REALM_LIST, "Realm List" },
58 { XFER_INITIATE, "Transfer Initiate" },
59 { XFER_DATA, "Transfer Data" },
60 { XFER_ACCEPT, "Transfer Accept" },
61 { XFER_RESUME, "Transfer Resume" },
62 { XFER_CANCEL, "Transfer Cancel" },
66 static const value_string account_type_vs[] = {
70 { 3, "Administrator" },
74 static const value_string realm_status_vs[] = {
81 static const value_string realm_type_vs[] = {
83 { 1, "Player versus player" },
85 { 6, "Role playing normal" },
86 { 8, "Role playing player versus player)" },
92 #define WOW_CLIENT_TO_SERVER pinfo->destport == WOW_PORT
93 #define WOW_SERVER_TO_CLIENT pinfo->srcport == WOW_PORT
95 /* Initialize the protocol and registered fields */
96 static int proto_wow = -1;
98 static int hf_wow_command = -1;
99 static int hf_wow_error = -1;
100 static int hf_wow_pkt_size = -1;
101 static int hf_wow_gamename = -1;
102 static int hf_wow_version1 = -1;
103 static int hf_wow_version2 = -1;
104 static int hf_wow_version3 = -1;
105 static int hf_wow_build = -1;
106 static int hf_wow_platform = -1;
107 static int hf_wow_os = -1;
108 static int hf_wow_country = -1;
109 static int hf_wow_timezone_bias = -1;
110 static int hf_wow_ip = -1;
111 static int hf_wow_srp_i_len = -1;
112 static int hf_wow_srp_i = -1;
114 static int hf_wow_srp_b = -1;
115 static int hf_wow_srp_g_len = -1;
116 static int hf_wow_srp_g = -1;
117 static int hf_wow_srp_n_len = -1;
118 static int hf_wow_srp_n = -1;
119 static int hf_wow_srp_s = -1;
121 static int hf_wow_srp_a = -1;
122 static int hf_wow_srp_m1 = -1;
123 static int hf_wow_crc_hash = -1;
124 static int hf_wow_num_keys = -1;
126 static int hf_wow_srp_m2 = -1;
128 static int hf_wow_num_realms = -1;
129 static int hf_wow_realm_type = -1;
130 static int hf_wow_realm_status = -1;
131 static int hf_wow_realm_color = -1;
132 static int hf_wow_realm_name = -1;
133 static int hf_wow_realm_socket = -1;
134 static int hf_wow_realm_population_level = -1;
135 static int hf_wow_realm_num_characters = -1;
136 static int hf_wow_realm_timezone = -1;
138 static gboolean wow_preference_desegment = TRUE;
140 static gint ett_wow = -1;
141 static gint ett_wow_realms = -1;
143 static void dissect_wow_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
144 static guint get_wow_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset);
148 dissect_wow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
150 gint8 size_field_offset = -1;
153 cmd = tvb_get_guint8(tvb, 0);
155 if(WOW_SERVER_TO_CLIENT && cmd == REALM_LIST)
156 size_field_offset = 1;
157 if(WOW_CLIENT_TO_SERVER && cmd == AUTH_LOGON_CHALLENGE)
158 size_field_offset = 2;
160 if(size_field_offset > -1) {
161 tcp_dissect_pdus(tvb, pinfo, tree, wow_preference_desegment,
162 size_field_offset+2, get_wow_pdu_len,
166 /* Doesn't have a size field, so it cannot span multiple
167 segments. Therefore, dissect this packet normally. */
168 dissect_wow_pdu(tvb, pinfo, tree);
175 get_wow_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
177 gint8 size_field_offset = -1;
181 cmd = tvb_get_guint8(tvb, offset);
183 if(WOW_SERVER_TO_CLIENT && cmd == REALM_LIST)
184 size_field_offset = 1;
185 if(WOW_CLIENT_TO_SERVER && cmd == AUTH_LOGON_CHALLENGE)
186 size_field_offset = 2;
188 pkt_len = tvb_get_letohs(tvb, size_field_offset);
190 return pkt_len + size_field_offset + 2;
195 dissect_wow_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
198 proto_tree *wow_tree, *wow_realms_tree;
200 gchar *string, *realm_name;
201 guint8 cmd, srp_i_len, srp_g_len, srp_n_len;
206 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WOW");
208 col_clear(pinfo->cinfo, COL_INFO);
210 cmd = tvb_get_guint8(tvb, offset);
212 if(check_col(pinfo->cinfo, COL_INFO)) {
213 col_set_str(pinfo->cinfo, COL_INFO,
214 val_to_str_const(cmd, cmd_vs,
215 "Unrecognized packet type"));
219 ti = proto_tree_add_item(tree, proto_wow, tvb, 0, -1, TRUE);
220 wow_tree = proto_item_add_subtree(ti, ett_wow);
222 proto_tree_add_item(wow_tree, hf_wow_command, tvb, offset, 1,
228 case AUTH_LOGON_CHALLENGE :
230 if(WOW_CLIENT_TO_SERVER) {
231 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
235 proto_tree_add_item(wow_tree, hf_wow_pkt_size,
236 tvb, offset, 2, TRUE);
239 string = g_strreverse(tvb_get_ephemeral_string(tvb, offset, 4));
240 proto_tree_add_string(wow_tree, hf_wow_gamename,
241 tvb, offset, 4, string);
244 proto_tree_add_item(wow_tree, hf_wow_version1,
245 tvb, offset, 1, TRUE);
248 proto_tree_add_item(wow_tree, hf_wow_version2,
249 tvb, offset, 1, TRUE);
252 proto_tree_add_item(wow_tree, hf_wow_version3,
253 tvb, offset, 1, TRUE);
256 proto_tree_add_item(wow_tree, hf_wow_build, tvb,
260 string = g_strreverse(tvb_get_ephemeral_string(tvb, offset, 4));
261 proto_tree_add_string(wow_tree, hf_wow_platform,
262 tvb, offset, 4, string);
265 string = g_strreverse(tvb_get_ephemeral_string(tvb, offset, 4));
266 proto_tree_add_string(wow_tree, hf_wow_os, tvb,
270 string = g_strreverse(tvb_get_ephemeral_string(tvb, offset, 4));
271 proto_tree_add_string(wow_tree, hf_wow_country,
272 tvb, offset, 4, string);
275 proto_tree_add_item(wow_tree,
276 hf_wow_timezone_bias,
277 tvb, offset, 4, TRUE);
280 proto_tree_add_item(wow_tree, hf_wow_ip, tvb,
284 proto_tree_add_item(wow_tree,
286 tvb, offset, 1, TRUE);
287 srp_i_len = tvb_get_guint8(tvb, offset);
290 proto_tree_add_item(wow_tree,
297 } else if(WOW_SERVER_TO_CLIENT) {
298 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
302 offset += 1; /* Unknown field */
304 proto_tree_add_item(wow_tree, hf_wow_srp_b, tvb,
308 proto_tree_add_item(wow_tree, hf_wow_srp_g_len,
309 tvb, offset, 1, TRUE);
310 srp_g_len = tvb_get_guint8(tvb, offset);
313 proto_tree_add_item(wow_tree, hf_wow_srp_g, tvb,
314 offset, srp_g_len, ENC_NA);
317 proto_tree_add_item(wow_tree, hf_wow_srp_n_len,
318 tvb, offset, 1, TRUE);
319 srp_n_len = tvb_get_guint8(tvb, offset);
322 proto_tree_add_item(wow_tree, hf_wow_srp_n, tvb,
323 offset, srp_n_len, ENC_NA);
326 proto_tree_add_item(wow_tree, hf_wow_srp_s, tvb,
330 offset += 16; /* Unknown field */
335 case AUTH_LOGON_PROOF :
337 if(WOW_CLIENT_TO_SERVER) {
338 proto_tree_add_item(wow_tree, hf_wow_srp_a, tvb,
342 proto_tree_add_item(wow_tree, hf_wow_srp_m1,
343 tvb, offset, 20, ENC_NA);
346 proto_tree_add_item(wow_tree, hf_wow_crc_hash,
347 tvb, offset, 20, ENC_NA);
350 proto_tree_add_item(wow_tree, hf_wow_num_keys,
351 tvb, offset, 1, TRUE);
354 offset += 1; /* Unknown field */
356 } else if(WOW_SERVER_TO_CLIENT) {
357 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
361 proto_tree_add_item(wow_tree, hf_wow_srp_m2,
362 tvb, offset, 20, ENC_NA);
365 offset += 4; /* Unknown field */
367 offset += 2; /* Unknown field */
374 if(WOW_CLIENT_TO_SERVER) {
377 } else if(WOW_SERVER_TO_CLIENT) {
379 proto_tree_add_item(wow_tree, hf_wow_pkt_size,
380 tvb, offset, 2, TRUE);
383 offset += 4; /* Unknown field; always 0 */
385 proto_tree_add_item(wow_tree, hf_wow_num_realms,
386 tvb, offset, 2, TRUE);
387 num_realms = tvb_get_letohs(tvb, offset);
390 for(i = 1; i <= num_realms; i++) {
391 realm_name = tvb_get_ephemeral_stringz(tvb,
395 ti = proto_tree_add_text(wow_tree, tvb,
400 wow_realms_tree = proto_item_add_subtree(ti, ett_wow_realms);
401 proto_tree_add_item(wow_realms_tree, hf_wow_realm_type, tvb, offset, 1, TRUE);
404 proto_tree_add_item(wow_realms_tree, hf_wow_realm_status, tvb, offset, 1, TRUE);
407 proto_tree_add_item(wow_realms_tree, hf_wow_realm_color, tvb, offset, 1, TRUE);
410 proto_tree_add_string(wow_realms_tree, hf_wow_realm_name, tvb, offset, len, realm_name);
413 string = tvb_get_ephemeral_stringz(tvb, offset,
415 proto_tree_add_string(wow_realms_tree, hf_wow_realm_socket, tvb, offset, len, string);
418 proto_tree_add_item(wow_realms_tree, hf_wow_realm_population_level, tvb, offset, 4, TRUE);
421 proto_tree_add_item(wow_realms_tree, hf_wow_realm_num_characters, tvb, offset, 1, TRUE);
424 proto_tree_add_item(wow_realms_tree, hf_wow_realm_timezone, tvb, offset, 1, TRUE);
427 offset += 1; /* Unknown field */
438 proto_register_wow(void)
440 module_t *wow_module; /* For our preferences */
442 static hf_register_info hf[] = {
444 { "Command", "wow.cmd",
445 FT_UINT8, BASE_HEX, VALS(cmd_vs), 0,
446 "Type of packet", HFILL }
450 { "Error", "wow.error",
451 FT_UINT8, BASE_DEC, 0, 0,
455 { "Packet size", "wow.pkt_size",
456 FT_UINT16, BASE_DEC, 0, 0,
460 { "Game name", "wow.gamename",
461 FT_STRING, BASE_NONE, 0, 0,
465 { "Version 1", "wow.version1",
466 FT_UINT8, BASE_DEC, 0, 0,
470 { "Version 2", "wow.version2",
471 FT_UINT8, BASE_DEC, 0, 0,
475 { "Version 3", "wow.version3",
476 FT_UINT8, BASE_DEC, 0, 0,
480 { "Build", "wow.build",
481 FT_UINT16, BASE_DEC, 0, 0,
485 { "Platform", "wow.platform",
486 FT_STRING, BASE_NONE, 0, 0,
487 "CPU architecture of client system", HFILL }
490 { "Operating system", "wow.os",
491 FT_STRING, BASE_NONE, 0, 0,
492 "Operating system of client system", HFILL }
495 { "Country", "wow.country",
496 FT_STRING, BASE_NONE, 0, 0,
497 "Language and country of client system", HFILL }
499 { &hf_wow_timezone_bias,
500 { "Timezone bias", "wow.timezone_bias",
501 FT_UINT32, BASE_DEC, 0, 0,
505 { "IP address", "wow.ip",
506 FT_IPv4, BASE_NONE, 0, 0,
507 "Client's actual IP address", HFILL }
510 { "SRP I length", "wow.srp.i_len",
511 FT_UINT8, BASE_DEC, 0, 0,
512 "Secure Remote Password protocol 'I' value length", HFILL }
515 { "SRP I", "wow.srp.i",
516 FT_STRING, BASE_NONE, 0, 0,
517 "Secure Remote Password protocol 'I' value (username)", HFILL }
520 { "SRP B", "wow.srp.b",
521 FT_BYTES, BASE_NONE, 0, 0,
522 "Secure Remote Password protocol 'B' value (one of the public ephemeral values)", HFILL }
525 { "SRP g length", "wow.srp.g_len",
526 FT_UINT8, BASE_DEC, 0, 0,
527 "Secure Remote Password protocol 'g' value length",
531 { "SRP g", "wow.srp.g",
532 FT_BYTES, BASE_NONE, 0, 0,
533 "Secure Remote Password protocol 'g' value", HFILL }
536 { "SRP N length", "wow.srp.n_len",
537 FT_UINT8, BASE_DEC, 0, 0,
538 "Secure Remote Password protocol 'N' value length",
542 { "SRP N", "wow.srp.n",
543 FT_BYTES, BASE_NONE, 0, 0,
544 "Secure Remote Password protocol 'N' value (a large safe prime)", HFILL }
547 { "SRP s", "wow.srp.s",
548 FT_BYTES, BASE_NONE, 0, 0,
549 "Secure Remote Password protocol 's' (user's salt) value",
553 { "SRP A", "wow.srp.a",
554 FT_BYTES, BASE_NONE, 0, 0,
555 "Secure Remote Password protocol 'A' value (one of the public ephemeral values)", HFILL }
558 { "SRP M1", "wow.srp.m1",
559 FT_BYTES, BASE_NONE, 0, 0,
560 "Secure Remote Password protocol 'M1' value", HFILL }
563 { "CRC hash", "wow.crc_hash",
564 FT_BYTES, BASE_NONE, 0, 0,
568 { "Number of keys", "wow.num_keys",
569 FT_UINT8, BASE_DEC, 0, 0,
573 { "SRP M2", "wow.srp.m2",
574 FT_BYTES, BASE_NONE, 0, 0,
575 "Secure Remote Password protocol 'M2' value", HFILL }
577 { &hf_wow_num_realms,
578 { "Number of realms", "wow.num_realms",
579 FT_UINT16, BASE_DEC, 0, 0,
582 { &hf_wow_realm_type,
583 { "Type", "wow.realm_type",
584 FT_UINT8, BASE_DEC, VALS(realm_type_vs), 0,
585 "Also known as realm icon", HFILL }
587 { &hf_wow_realm_status,
588 { "Status", "wow.realm_status",
589 FT_UINT8, BASE_DEC, VALS(realm_status_vs), 0,
592 { &hf_wow_realm_color,
593 { "Color", "wow.realm_color",
594 FT_UINT8, BASE_DEC, 0, 0,
597 { &hf_wow_realm_name,
598 { "Name", "wow.realm_name",
599 FT_STRINGZ, BASE_NONE, 0, 0,
602 { &hf_wow_realm_socket,
603 { "Server socket", "wow.realm_socket",
604 FT_STRINGZ, BASE_NONE, 0, 0,
605 "IP address and port to connect to on the server to reach this realm", HFILL }
607 { &hf_wow_realm_population_level,
608 { "Population level", "wow.realm_population_level",
609 FT_FLOAT, BASE_NONE, 0, 0,
612 { &hf_wow_realm_num_characters,
613 { "Number of characters", "wow.realm_num_characters",
614 FT_UINT8, BASE_DEC, 0, 0,
615 "Number of characters the user has in this realm", HFILL }
617 { &hf_wow_realm_timezone,
618 { "Timezone", "wow.realm_timezone",
619 FT_UINT8, BASE_DEC, 0, 0,
624 static gint *ett[] = {
629 proto_wow = proto_register_protocol("World of Warcraft",
632 proto_register_field_array(proto_wow, hf, array_length(hf));
633 proto_register_subtree_array(ett, array_length(ett));
635 wow_module = prefs_register_protocol(proto_wow, NULL);
637 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);
642 proto_reg_handoff_wow(void)
644 dissector_handle_t wow_handle;
646 wow_handle = new_create_dissector_handle(dissect_wow, proto_wow);
647 dissector_add_uint("tcp.port", WOW_PORT, wow_handle);