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" },
63 static const value_string account_type_vs
[] = {
67 { 3, "Administrator" },
72 static const value_string realm_status_vs
[] = {
79 static const value_string realm_type_vs
[] = {
81 { 1, "Player versus player" },
83 { 6, "Role playing normal" },
84 { 8, "Role playing player versus player)" },
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;
142 get_wow_pdu_len(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
)
144 gint8 size_field_offset
= -1;
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;
162 dissect_wow_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
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
;
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"));
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,
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
);
200 proto_tree_add_item(wow_tree
, hf_wow_pkt_size
,
201 tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
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
);
209 proto_tree_add_item(wow_tree
, hf_wow_version1
,
210 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
213 proto_tree_add_item(wow_tree
, hf_wow_version2
,
214 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
217 proto_tree_add_item(wow_tree
, hf_wow_version3
,
218 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
221 proto_tree_add_item(wow_tree
, hf_wow_build
, tvb
,
222 offset
, 2, ENC_LITTLE_ENDIAN
);
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
);
230 string
= g_strreverse(tvb_get_string(wmem_packet_scope(), tvb
, offset
, 4));
231 proto_tree_add_string(wow_tree
, hf_wow_os
, tvb
,
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
);
240 proto_tree_add_item(wow_tree
,
241 hf_wow_timezone_bias
,
242 tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
245 proto_tree_add_item(wow_tree
, hf_wow_ip
, tvb
,
246 offset
, 4, ENC_BIG_ENDIAN
);
249 proto_tree_add_item(wow_tree
,
251 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
252 srp_i_len
= tvb_get_guint8(tvb
, offset
);
255 proto_tree_add_item(wow_tree
,
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
);
267 offset
+= 1; /* Unknown field */
269 proto_tree_add_item(wow_tree
, hf_wow_srp_b
, tvb
,
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
);
278 proto_tree_add_item(wow_tree
, hf_wow_srp_g
, tvb
,
279 offset
, srp_g_len
, ENC_NA
);
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
);
287 proto_tree_add_item(wow_tree
, hf_wow_srp_n
, tvb
,
288 offset
, srp_n_len
, ENC_NA
);
291 proto_tree_add_item(wow_tree
, hf_wow_srp_s
, tvb
,
295 /*offset += 16;*/ /* Unknown field */
300 case AUTH_LOGON_PROOF
:
302 if(WOW_CLIENT_TO_SERVER
) {
303 proto_tree_add_item(wow_tree
, hf_wow_srp_a
, tvb
,
307 proto_tree_add_item(wow_tree
, hf_wow_srp_m1
,
308 tvb
, offset
, 20, ENC_NA
);
311 proto_tree_add_item(wow_tree
, hf_wow_crc_hash
,
312 tvb
, offset
, 20, ENC_NA
);
315 proto_tree_add_item(wow_tree
, hf_wow_num_keys
,
316 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
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
);
326 proto_tree_add_item(wow_tree
, hf_wow_srp_m2
,
327 tvb
, offset
, 20, ENC_NA
);
330 /*offset += 4;*/ /* Unknown field */
332 /*offset += 2;*/ /* Unknown field */
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
);
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
);
355 for(ii
= 0; ii
< num_realms
; ii
++) {
356 realm_name
= tvb_get_stringz(wmem_packet_scope(), tvb
,
360 ti
= proto_tree_add_text(wow_tree
, tvb
,
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
);
369 proto_tree_add_item(wow_realms_tree
, hf_wow_realm_status
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
372 proto_tree_add_item(wow_realms_tree
, hf_wow_realm_color
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
375 proto_tree_add_string(wow_realms_tree
, hf_wow_realm_name
, tvb
, offset
, len
, realm_name
);
378 string
= tvb_get_stringz(wmem_packet_scope(), tvb
, offset
,
380 proto_tree_add_string(wow_realms_tree
, hf_wow_realm_socket
, tvb
, offset
, len
, string
);
383 proto_tree_add_item(wow_realms_tree
, hf_wow_realm_population_level
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
386 proto_tree_add_item(wow_realms_tree
, hf_wow_realm_num_characters
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
389 proto_tree_add_item(wow_realms_tree
, hf_wow_realm_timezone
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
392 offset
+= 1; /* Unknown field */
400 return tvb_length(tvb
);
404 dissect_wow(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
406 gint8 size_field_offset
= -1;
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
);
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
);
432 proto_register_wow(void)
434 module_t
*wow_module
; /* For our preferences */
436 static hf_register_info hf
[] = {
438 { "Command", "wow.cmd",
439 FT_UINT8
, BASE_HEX
, VALS(cmd_vs
), 0,
440 "Type of packet", HFILL
}
444 { "Error", "wow.error",
445 FT_UINT8
, BASE_DEC
, 0, 0,
449 { "Packet size", "wow.pkt_size",
450 FT_UINT16
, BASE_DEC
, 0, 0,
454 { "Game name", "wow.gamename",
455 FT_STRING
, BASE_NONE
, 0, 0,
459 { "Version 1", "wow.version1",
460 FT_UINT8
, BASE_DEC
, 0, 0,
464 { "Version 2", "wow.version2",
465 FT_UINT8
, BASE_DEC
, 0, 0,
469 { "Version 3", "wow.version3",
470 FT_UINT8
, BASE_DEC
, 0, 0,
474 { "Build", "wow.build",
475 FT_UINT16
, BASE_DEC
, 0, 0,
479 { "Platform", "wow.platform",
480 FT_STRING
, BASE_NONE
, 0, 0,
481 "CPU architecture of client system", HFILL
}
484 { "Operating system", "wow.os",
485 FT_STRING
, BASE_NONE
, 0, 0,
486 "Operating system of client system", HFILL
}
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,
499 { "IP address", "wow.ip",
500 FT_IPv4
, BASE_NONE
, 0, 0,
501 "Client's actual IP address", HFILL
}
504 { "SRP I length", "wow.srp.i_len",
505 FT_UINT8
, BASE_DEC
, 0, 0,
506 "Secure Remote Password protocol 'I' value length", HFILL
}
509 { "SRP I", "wow.srp.i",
510 FT_STRING
, BASE_NONE
, 0, 0,
511 "Secure Remote Password protocol 'I' value (username)", HFILL
}
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
}
519 { "SRP g length", "wow.srp.g_len",
520 FT_UINT8
, BASE_DEC
, 0, 0,
521 "Secure Remote Password protocol 'g' value length",
525 { "SRP g", "wow.srp.g",
526 FT_BYTES
, BASE_NONE
, 0, 0,
527 "Secure Remote Password protocol 'g' value", HFILL
}
530 { "SRP N length", "wow.srp.n_len",
531 FT_UINT8
, BASE_DEC
, 0, 0,
532 "Secure Remote Password protocol 'N' value length",
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
}
541 { "SRP s", "wow.srp.s",
542 FT_BYTES
, BASE_NONE
, 0, 0,
543 "Secure Remote Password protocol 's' (user's salt) value",
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
}
552 { "SRP M1", "wow.srp.m1",
553 FT_BYTES
, BASE_NONE
, 0, 0,
554 "Secure Remote Password protocol 'M1' value", HFILL
}
557 { "CRC hash", "wow.crc_hash",
558 FT_BYTES
, BASE_NONE
, 0, 0,
562 { "Number of keys", "wow.num_keys",
563 FT_UINT8
, BASE_DEC
, 0, 0,
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,
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,
586 { &hf_wow_realm_color
,
587 { "Color", "wow.realm_color",
588 FT_UINT8
, BASE_DEC
, 0, 0,
591 { &hf_wow_realm_name
,
592 { "Name", "wow.realm_name",
593 FT_STRINGZ
, BASE_NONE
, 0, 0,
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,
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,
618 static gint
*ett
[] = {
623 proto_wow
= proto_register_protocol("World of Warcraft",
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
);
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
);