2 * Routines for World of Warcraft (WoW) protocol dissection
3 * Copyright 2008-2009, Stephen Fisher <stephentfisher@yahoo.com>
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." */
41 #include <epan/packet.h>
42 #include <epan/prefs.h>
43 #include "packet-tcp.h"
46 AUTH_LOGON_CHALLENGE = 0x00,
47 AUTH_LOGON_PROOF = 0x01,
56 static const value_string cmd_vs[] = {
57 { AUTH_LOGON_CHALLENGE, "Authentication Logon Challenge" },
58 { AUTH_LOGON_PROOF, "Authentication Logon Proof" },
59 { REALM_LIST, "Realm List" },
60 { XFER_INITIATE, "Transfer Initiate" },
61 { XFER_DATA, "Transfer Data" },
62 { XFER_ACCEPT, "Transfer Accept" },
63 { XFER_RESUME, "Transfer Resume" },
64 { XFER_CANCEL, "Transfer Cancel" },
68 static const value_string account_type_vs[] = {
72 { 3, "Administrator" },
76 static const value_string realm_status_vs[] = {
83 static const value_string realm_type_vs[] = {
85 { 1, "Player versus player" },
87 { 6, "Role playing normal" },
88 { 8, "Role playing player versus player)" },
94 #define WOW_CLIENT_TO_SERVER pinfo->destport == WOW_PORT
95 #define WOW_SERVER_TO_CLIENT pinfo->srcport == WOW_PORT
97 /* Forward declaration we need below */
98 void proto_reg_handoff_wow(void);
100 /* Initialize the protocol and registered fields */
101 static int proto_wow = -1;
103 static int hf_wow_command = -1;
104 static int hf_wow_error = -1;
105 static int hf_wow_pkt_size = -1;
106 static int hf_wow_gamename = -1;
107 static int hf_wow_version1 = -1;
108 static int hf_wow_version2 = -1;
109 static int hf_wow_version3 = -1;
110 static int hf_wow_build = -1;
111 static int hf_wow_platform = -1;
112 static int hf_wow_os = -1;
113 static int hf_wow_country = -1;
114 static int hf_wow_timezone_bias = -1;
115 static int hf_wow_ip = -1;
116 static int hf_wow_srp_i_len = -1;
117 static int hf_wow_srp_i = -1;
119 static int hf_wow_srp_b = -1;
120 static int hf_wow_srp_g_len = -1;
121 static int hf_wow_srp_g = -1;
122 static int hf_wow_srp_n_len = -1;
123 static int hf_wow_srp_n = -1;
124 static int hf_wow_srp_s = -1;
126 static int hf_wow_srp_a = -1;
127 static int hf_wow_srp_m1 = -1;
128 static int hf_wow_crc_hash = -1;
129 static int hf_wow_num_keys = -1;
131 static int hf_wow_srp_m2 = -1;
133 static int hf_wow_num_realms = -1;
134 static int hf_wow_realm_type = -1;
135 static int hf_wow_realm_status = -1;
136 static int hf_wow_realm_color = -1;
137 static int hf_wow_realm_name = -1;
138 static int hf_wow_realm_socket = -1;
139 static int hf_wow_realm_population_level = -1;
140 static int hf_wow_realm_num_characters = -1;
141 static int hf_wow_realm_timezone = -1;
143 static gboolean wow_preference_desegment = TRUE;
145 static gint ett_wow = -1;
146 static gint ett_wow_realms = -1;
148 static void dissect_wow_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
149 static guint get_wow_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset);
153 dissect_wow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
155 gint8 size_field_offset = -1;
158 cmd = tvb_get_guint8(tvb, 0);
160 if(WOW_SERVER_TO_CLIENT && cmd == REALM_LIST)
161 size_field_offset = 1;
162 if(WOW_CLIENT_TO_SERVER && cmd == AUTH_LOGON_CHALLENGE)
163 size_field_offset = 2;
165 if(size_field_offset > -1) {
166 tcp_dissect_pdus(tvb, pinfo, tree, wow_preference_desegment,
167 size_field_offset+2, get_wow_pdu_len,
171 /* Doesn't have a size field, so it cannot span multiple
172 segments. Therefore, dissect this packet normally. */
173 dissect_wow_pdu(tvb, pinfo, tree);
180 get_wow_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
182 gint8 size_field_offset = -1;
186 cmd = tvb_get_guint8(tvb, offset);
188 if(WOW_SERVER_TO_CLIENT && cmd == REALM_LIST)
189 size_field_offset = 1;
190 if(WOW_CLIENT_TO_SERVER && cmd == AUTH_LOGON_CHALLENGE)
191 size_field_offset = 2;
193 pkt_len = tvb_get_letohs(tvb, size_field_offset);
195 return pkt_len + size_field_offset + 2;
200 dissect_wow_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
203 proto_tree *wow_tree, *wow_realms_tree;
205 gchar *string, *realm_name;
206 guint8 cmd, srp_i_len, srp_g_len, srp_n_len;
211 if(check_col(pinfo->cinfo, COL_PROTOCOL))
212 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WOW");
214 if(check_col(pinfo->cinfo, COL_INFO))
215 col_clear(pinfo->cinfo, COL_INFO);
217 cmd = tvb_get_guint8(tvb, offset);
219 if(check_col(pinfo->cinfo, COL_INFO)) {
220 col_set_str(pinfo->cinfo, COL_INFO,
221 val_to_str(cmd, cmd_vs,
222 "Unrecognized packet type"));
226 ti = proto_tree_add_item(tree, proto_wow, tvb, 0, -1, TRUE);
227 wow_tree = proto_item_add_subtree(ti, ett_wow);
229 proto_tree_add_item(wow_tree, hf_wow_command, tvb, offset, 1,
235 case AUTH_LOGON_CHALLENGE :
237 if(WOW_CLIENT_TO_SERVER) {
238 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
242 proto_tree_add_item(wow_tree, hf_wow_pkt_size,
243 tvb, offset, 2, TRUE);
246 string = g_strreverse(tvb_get_string(tvb, offset, 4));
247 proto_tree_add_string(wow_tree, hf_wow_gamename,
248 tvb, offset, 4, string);
252 proto_tree_add_item(wow_tree, hf_wow_version1,
253 tvb, offset, 1, TRUE);
256 proto_tree_add_item(wow_tree, hf_wow_version2,
257 tvb, offset, 1, TRUE);
260 proto_tree_add_item(wow_tree, hf_wow_version3,
261 tvb, offset, 1, TRUE);
264 proto_tree_add_item(wow_tree, hf_wow_build, tvb,
268 string = g_strreverse(tvb_get_string(tvb, offset, 4));
269 proto_tree_add_string(wow_tree, hf_wow_platform,
270 tvb, offset, 4, string);
274 string = g_strreverse(tvb_get_string(tvb, offset, 4));
275 proto_tree_add_string(wow_tree, hf_wow_os, tvb,
280 string = g_strreverse(tvb_get_string(tvb, offset, 4));
281 proto_tree_add_string(wow_tree, hf_wow_country,
282 tvb, offset, 4, string);
286 proto_tree_add_item(wow_tree,
287 hf_wow_timezone_bias,
288 tvb, offset, 4, TRUE);
291 proto_tree_add_item(wow_tree, hf_wow_ip, tvb,
295 proto_tree_add_item(wow_tree,
297 tvb, offset, 1, TRUE);
298 srp_i_len = tvb_get_guint8(tvb, offset);
301 proto_tree_add_item(wow_tree,
308 } else if(WOW_SERVER_TO_CLIENT) {
309 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
313 offset += 1; /* Unknown field */
315 proto_tree_add_item(wow_tree, hf_wow_srp_b, tvb,
319 proto_tree_add_item(wow_tree, hf_wow_srp_g_len,
320 tvb, offset, 1, TRUE);
321 srp_g_len = tvb_get_guint8(tvb, offset);
324 proto_tree_add_item(wow_tree, hf_wow_srp_g, tvb,
325 offset, srp_g_len, TRUE);
328 proto_tree_add_item(wow_tree, hf_wow_srp_n_len,
329 tvb, offset, 1, TRUE);
330 srp_n_len = tvb_get_guint8(tvb, offset);
333 proto_tree_add_item(wow_tree, hf_wow_srp_n, tvb,
334 offset, srp_n_len, TRUE);
337 proto_tree_add_item(wow_tree, hf_wow_srp_s, tvb,
341 offset += 16; /* Unknown field */
346 case AUTH_LOGON_PROOF :
348 if(WOW_CLIENT_TO_SERVER) {
349 proto_tree_add_item(wow_tree, hf_wow_srp_a, tvb,
353 proto_tree_add_item(wow_tree, hf_wow_srp_m1,
354 tvb, offset, 20, TRUE);
357 proto_tree_add_item(wow_tree, hf_wow_crc_hash,
358 tvb, offset, 20, TRUE);
361 proto_tree_add_item(wow_tree, hf_wow_num_keys,
362 tvb, offset, 1, TRUE);
365 offset += 1; /* Unknown field */
367 } else if(WOW_SERVER_TO_CLIENT) {
368 proto_tree_add_item(wow_tree, hf_wow_error, tvb,
372 proto_tree_add_item(wow_tree, hf_wow_srp_m2,
373 tvb, offset, 20, TRUE);
376 offset += 4; /* Unknown field */
378 offset += 2; /* Unknown field */
385 if(WOW_CLIENT_TO_SERVER) {
388 } else if(WOW_SERVER_TO_CLIENT) {
390 proto_tree_add_item(wow_tree, hf_wow_pkt_size,
391 tvb, offset, 2, TRUE);
394 offset += 4; /* Unknown field; always 0 */
396 proto_tree_add_item(wow_tree, hf_wow_num_realms,
397 tvb, offset, 2, TRUE);
398 num_realms = tvb_get_letohs(tvb, offset);
401 for(i = 1; i <= num_realms; i++) {
402 realm_name = tvb_get_stringz(tvb,
406 ti = proto_tree_add_text(wow_tree, tvb,
411 wow_realms_tree = proto_item_add_subtree(ti, ett_wow_realms);
412 proto_tree_add_item(wow_realms_tree, hf_wow_realm_type, tvb, offset, 1, TRUE);
415 proto_tree_add_item(wow_realms_tree, hf_wow_realm_status, tvb, offset, 1, TRUE);
418 proto_tree_add_item(wow_realms_tree, hf_wow_realm_color, tvb, offset, 1, TRUE);
421 proto_tree_add_string(wow_realms_tree, hf_wow_realm_name, tvb, offset, len, realm_name);
425 string = tvb_get_stringz(tvb, offset,
427 proto_tree_add_string(wow_realms_tree, hf_wow_realm_socket, tvb, offset, len, string);
431 proto_tree_add_item(wow_realms_tree, hf_wow_realm_population_level, tvb, offset, 4, TRUE);
434 proto_tree_add_item(wow_realms_tree, hf_wow_realm_num_characters, tvb, offset, 1, TRUE);
437 proto_tree_add_item(wow_realms_tree, hf_wow_realm_timezone, tvb, offset, 1, TRUE);
440 offset += 1; /* Unknown field */
451 proto_register_wow(void)
453 module_t *wow_module; /* For our preferences */
455 static hf_register_info hf[] = {
457 { "Command", "wow.cmd",
458 FT_UINT8, BASE_HEX, VALS(cmd_vs), 0,
459 "Type of packet", HFILL }
463 { "Error", "wow.error",
464 FT_UINT8, BASE_DEC, 0, 0,
468 { "Packet size", "wow.pkt_size",
469 FT_UINT16, BASE_DEC, 0, 0,
473 { "Game name", "wow.gamename",
474 FT_STRING, BASE_NONE, 0, 0,
478 { "Version 1", "wow.version1",
479 FT_UINT8, BASE_DEC, 0, 0,
483 { "Version 2", "wow.version2",
484 FT_UINT8, BASE_DEC, 0, 0,
488 { "Version 3", "wow.version3",
489 FT_UINT8, BASE_DEC, 0, 0,
493 { "Build", "wow.build",
494 FT_UINT16, BASE_DEC, 0, 0,
498 { "Platform", "wow.platform",
499 FT_STRING, BASE_NONE, 0, 0,
500 "CPU architecture of client system", HFILL }
503 { "Operating system", "wow.os",
504 FT_STRING, BASE_NONE, 0, 0,
505 "Operating system of client system", HFILL }
508 { "Country", "wow.country",
509 FT_STRING, BASE_NONE, 0, 0,
510 "Language and country of client system", HFILL }
512 { &hf_wow_timezone_bias,
513 { "Timezone bias", "wow.timezone_bias",
514 FT_UINT32, BASE_DEC, 0, 0,
518 { "IP address", "wow.ip",
519 FT_IPv4, BASE_NONE, 0, 0,
520 "Client's actual IP address", HFILL }
523 { "SRP I length", "wow.srp.i_len",
524 FT_UINT8, BASE_DEC, 0, 0,
525 "Secure Remote Password protocol 'I' value length", HFILL }
528 { "SRP I", "wow.srp.i",
529 FT_STRING, BASE_NONE, 0, 0,
530 "Secure Remote Password protocol 'I' value (username)", HFILL }
533 { "SRP B", "wow.srp.b",
534 FT_BYTES, BASE_NONE, 0, 0,
535 "Secure Remote Password protocol 'B' value (one of the public ephemeral values)", HFILL }
538 { "SRP g length", "wow.srp.g_len",
539 FT_UINT8, BASE_DEC, 0, 0,
540 "Secure Remote Password protocol 'g' value length",
544 { "SRP g", "wow.srp.g",
545 FT_BYTES, BASE_NONE, 0, 0,
546 "Secure Remote Password protocol 'g' value", HFILL }
549 { "SRP N length", "wow.srp.n_len",
550 FT_UINT8, BASE_DEC, 0, 0,
551 "Secure Remote Password protocol 'N' value length",
555 { "SRP N", "wow.srp.n",
556 FT_BYTES, BASE_NONE, 0, 0,
557 "Secure Remote Password protocol 'N' value (a large safe prime)", HFILL }
560 { "SRP s", "wow.srp.s",
561 FT_BYTES, BASE_NONE, 0, 0,
562 "Secure Remote Password protocol 's' (user's salt) value",
566 { "SRP A", "wow.srp.a",
567 FT_BYTES, BASE_NONE, 0, 0,
568 "Secure Remote Password protocol 'A' value (one of the public ephemeral values)", HFILL }
571 { "SRP M1", "wow.srp.m1",
572 FT_BYTES, BASE_NONE, 0, 0,
573 "Secure Remote Password protocol 'M1' value ", HFILL }
576 { "CRC hash", "wow.crc_hash",
577 FT_BYTES, BASE_NONE, 0, 0,
581 { "Number of keys", "wow.num_keys",
582 FT_UINT8, BASE_DEC, 0, 0,
586 { "SRP M2", "wow.srp.m2",
587 FT_BYTES, BASE_NONE, 0, 0,
588 "Secure Remote Password protocol 'M2' value", HFILL }
590 { &hf_wow_num_realms,
591 { "Number of realms", "wow.num_realms",
592 FT_UINT16, BASE_DEC, 0, 0,
595 { &hf_wow_realm_type,
596 { "Type", "wow.realm_type",
597 FT_UINT8, BASE_DEC, VALS(realm_type_vs), 0,
598 "Also known as realm icon", HFILL }
600 { &hf_wow_realm_status,
601 { "Status", "wow.realm_status",
602 FT_UINT8, BASE_DEC, VALS(realm_status_vs), 0,
605 { &hf_wow_realm_color,
606 { "Color", "wow.realm_color",
607 FT_UINT8, BASE_DEC, 0, 0,
610 { &hf_wow_realm_name,
611 { "Name", "wow.realm_name",
612 FT_STRINGZ, BASE_NONE, 0, 0,
615 { &hf_wow_realm_socket,
616 { "Server socket", "wow.realm_socket",
617 FT_STRINGZ, BASE_NONE, 0, 0,
618 "IP address and port to connect to on the server to reach this realm", HFILL }
620 { &hf_wow_realm_population_level,
621 { "Population level", "wow.realm_population_level",
622 FT_FLOAT, BASE_NONE, 0, 0,
625 { &hf_wow_realm_num_characters,
626 { "Number of characters", "wow.realm_num_characters",
627 FT_UINT8, BASE_DEC, 0, 0,
628 "Number of characters the user has in this realm", HFILL }
630 { &hf_wow_realm_timezone,
631 { "Timezone", "wow.realm_timezone",
632 FT_UINT8, BASE_DEC, 0, 0,
637 static gint *ett[] = {
642 proto_wow = proto_register_protocol("World of Warcraft",
645 proto_register_field_array(proto_wow, hf, array_length(hf));
646 proto_register_subtree_array(ett, array_length(ett));
648 wow_module = prefs_register_protocol(proto_wow, proto_reg_handoff_wow);
650 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);
655 proto_reg_handoff_wow(void)
657 static gboolean inited = FALSE;
660 dissector_handle_t wow_handle;
662 wow_handle = new_create_dissector_handle(dissect_wow,
664 dissector_add("tcp.port", WOW_PORT, wow_handle);