|  | /* | 
|  | * Copyright 2010 Google Inc. | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); you may not | 
|  | * use this file except in compliance with the License. You may obtain a copy of | 
|  | * the License at | 
|  | * | 
|  | * http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
|  | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | 
|  | * License for the specific language governing permissions and limitations under | 
|  | * the License. | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * Note that Wireshark dissectors are pure C, not C++ -- there are also | 
|  | * restrictions on various C extensions, including things like all variables | 
|  | * must be declared at the beginning of a block, and only initialized to | 
|  | * scalar constants. | 
|  | */ | 
|  | #ifdef HAVE_CONFIG_H | 
|  | #include "config.h" | 
|  | #endif | 
|  |  | 
|  | #include "BrowserChannel.h" | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #include <gmodule.h> | 
|  | #include <epan/conversation.h> | 
|  | #include <epan/prefs.h> | 
|  | #include <epan/packet.h> | 
|  |  | 
|  | /* | 
|  | * Default port to follow. | 
|  | */ | 
|  | #define DEFAULT_GWTCS_PORT 9997 | 
|  |  | 
|  | /* | 
|  | * Trim strngs at this length. | 
|  | */ | 
|  | #define MAX_STRING_LENGTH 100 | 
|  |  | 
|  | /* forward reference */ | 
|  | void proto_register_gwtcs(); | 
|  | void proto_reg_handoff_gwtcs(); | 
|  |  | 
|  | /* Define version if we are not building Wireshark statically */ | 
|  | #ifndef ENABLE_STATIC | 
|  | G_MODULE_EXPORT const gchar version[] = "0.1"; | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * Data stored for a GWT-CS conversation. | 
|  | */ | 
|  | typedef struct _gwtcs_data { | 
|  | address       clientAddress; | 
|  | guint32       clientPort; | 
|  | int           level; | 
|  | } gwtcs_data; | 
|  |  | 
|  | /* | 
|  | * Names of packet types -- must be in order. | 
|  | */ | 
|  | static const value_string packetTypes[] = { | 
|  | { MESSAGE_TYPE_INVOKE,                  "Invoke" }, | 
|  | { MESSAGE_TYPE_RETURN,                  "Return" }, | 
|  | { MESSAGE_TYPE_OLD_LOAD_MODULE,         "Old Load Module" }, | 
|  | { MESSAGE_TYPE_QUIT,                    "Quit" }, | 
|  | { MESSAGE_TYPE_LOADJSNI,                "Load JSNI" }, | 
|  | { MESSAGE_TYPE_INVOKESPECIAL,           "Invoke Special" }, | 
|  | { MESSAGE_TYPE_FREEVALUE,               "Free Value" }, | 
|  | { MESSAGE_TYPE_FATAL_ERROR,             "Fatal Error" }, | 
|  | { MESSAGE_TYPE_CHECK_VERSIONS,          "Check Versions" }, | 
|  | { MESSAGE_TYPE_PROTOCOL_VERSION,        "Protocol Version" }, | 
|  | { MESSAGE_TYPE_CHOOSE_TRANSPORT,        "Choose Transport" }, | 
|  | { MESSAGE_TYPE_SWITCH_TRANSPORT,        "Switch Transport" }, | 
|  | { MESSAGE_TYPE_LOAD_MODULE,             "Load Module" }, | 
|  | { 0,  NULL } | 
|  | }; | 
|  | #define MAX_PACKET_TYPE MESSAGE_TYPE_LOAD_MODULE | 
|  |  | 
|  |  | 
|  | static const value_string valueTypes[] = { | 
|  | {VALUE_TYPE_NULL,        "null" }, | 
|  | {VALUE_TYPE_BOOLEAN,     "boolean" }, | 
|  | {VALUE_TYPE_BYTE,        "byte" }, | 
|  | {VALUE_TYPE_CHAR,        "char" }, | 
|  | {VALUE_TYPE_SHORT,       "short" }, | 
|  | {VALUE_TYPE_INT,         "int" }, | 
|  | {VALUE_TYPE_LONG,        "long" }, | 
|  | {VALUE_TYPE_FLOAT,       "float" }, | 
|  | {VALUE_TYPE_DOUBLE,      "double" }, | 
|  | {VALUE_TYPE_STRING,      "string" }, | 
|  | {VALUE_TYPE_JAVA_OBJECT, "Java object" }, | 
|  | {VALUE_TYPE_JS_OBJECT,   "JS object" }, | 
|  | {VALUE_TYPE_UNDEFINED,   "undefined" }, | 
|  | { 0,  NULL } | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * InvokeSpecial types -- must be in order. | 
|  | */ | 
|  | static const value_string specialTypes[] = { | 
|  | { SPECIAL_HAS_METHOD,   "hasMethod" }, | 
|  | { SPECIAL_HAS_PROPERTY, "hasProperty" }, | 
|  | { SPECIAL_GET_PROPERTY, "getProperty" }, | 
|  | { SPECIAL_SET_PROPERTY, "setProperty" }, | 
|  | { 0, NULL } | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * Dynamically assigned protocol ID. | 
|  | */ | 
|  | static int proto_gwtcs = -1; | 
|  |  | 
|  | /* | 
|  | * Dynamically assigned subtree IDs. | 
|  | */ | 
|  | static gint ett_gwtcs = -1; | 
|  | static gint ett_value = -1; | 
|  | static gint ett_args = -1; | 
|  |  | 
|  | /* | 
|  | * IDs for displayed values. | 
|  | */ | 
|  | static int hf_gwtcs_pdu_type = -1; | 
|  | static int hf_gwtcs_value_tag = -1; | 
|  | static int hf_gwtcs_min_vers = -1; | 
|  | static int hf_gwtcs_max_vers = -1; | 
|  | static int hf_gwtcs_hosted_vers = -1; | 
|  | static int hf_gwtcs_sel_vers = -1; | 
|  | static int hf_gwtcs_lm_ua = -1; | 
|  | static int hf_gwtcs_lm_tabkey = -1; | 
|  | static int hf_gwtcs_lm_seskey = -1; | 
|  | static int hf_gwtcs_lm_modname = -1; | 
|  | static int hf_gwtcs_lm_url = -1; | 
|  | static int hf_gwtcs_methname = -1; | 
|  | static int hf_gwtcs_isexc = -1; | 
|  | static int hf_gwtcs_dispid = -1; | 
|  | static int hf_gwtcs_jsni = -1; | 
|  | static int hf_gwtcs_val_hdr = -1; | 
|  | static int hf_gwtcs_val_bool = -1; | 
|  | static int hf_gwtcs_val_byte = -1; | 
|  | static int hf_gwtcs_val_char = -1; | 
|  | static int hf_gwtcs_val_short = -1; | 
|  | static int hf_gwtcs_val_int = -1; | 
|  | static int hf_gwtcs_val_long = -1; | 
|  | static int hf_gwtcs_val_float = -1; | 
|  | static int hf_gwtcs_val_double = -1; | 
|  | static int hf_gwtcs_val_string = -1; | 
|  | static int hf_gwtcs_val_javaobj = -1; | 
|  | static int hf_gwtcs_val_jsobj = -1; | 
|  | static int hf_gwtcs_val_null = -1; | 
|  | static int hf_gwtcs_val_undef = -1; | 
|  | static int hf_gwtcs_numargs = -1; | 
|  | static int hf_gwtcs_spectype = -1; | 
|  | static int hf_gwtcs_transport = -1; | 
|  | static int hf_gwtcs_transargs = -1; | 
|  |  | 
|  | static dissector_handle_t gwtcs_handle; | 
|  |  | 
|  | static GMemChunk* memChunk = 0; | 
|  |  | 
|  | #ifndef ENABLE_STATIC | 
|  | G_MODULE_EXPORT void plugin_register(void) | 
|  | { | 
|  | /* register the new protocol, protocol fields, and subtrees */ | 
|  | if (proto_gwtcs == -1) { /* execute protocol initialization only once */ | 
|  | proto_register_gwtcs(); | 
|  | } | 
|  | } | 
|  |  | 
|  | G_MODULE_EXPORT void plugin_reg_handoff(void){ | 
|  | proto_reg_handoff_gwtcs(); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * Get a string describing a Value from the packet, and return the total length | 
|  | * (including the tag byte). | 
|  | * | 
|  | * ofs - offset into the buffer of the Value's tag byte | 
|  | * buf - buffer to write string into; on return is guaranteed to be null | 
|  | *     terminated | 
|  | * buflen - length of buf | 
|  | * | 
|  | * returns the offset after the last byte of this Value | 
|  | */ | 
|  | static int getValue(tvbuff_t* tvb, int ofs, char* buf, int buflen) { | 
|  | guint8 tag; | 
|  | tag = tvb_get_guint8(tvb, ofs++); | 
|  | int len = 0; | 
|  | switch (tag) { | 
|  | case VALUE_TYPE_NULL: | 
|  | strncpy(buf, "null", buflen); | 
|  | break; | 
|  | case VALUE_TYPE_UNDEFINED: | 
|  | strncpy(buf, "undef", buflen); | 
|  | break; | 
|  | case VALUE_TYPE_BOOLEAN: | 
|  | { | 
|  | guint8 val; | 
|  | val = tvb_get_guint8(tvb, ofs); | 
|  | len = 1; | 
|  | strncpy(buf, val ? "true" : "false", buflen); | 
|  | } | 
|  | break; | 
|  | case VALUE_TYPE_BYTE: | 
|  | { | 
|  | int val; | 
|  | val = tvb_get_guint8(tvb, ofs); | 
|  | if (val & 128) { | 
|  | val -= 256; | 
|  | } | 
|  | len = 1; | 
|  | snprintf(buf, buflen, "%d", val); | 
|  | } | 
|  | break; | 
|  | case VALUE_TYPE_SHORT: | 
|  | { | 
|  | int val; | 
|  | val = tvb_get_ntohs(tvb, ofs); | 
|  | if (val & 0x8000) { | 
|  | val -= 0x10000; | 
|  | } | 
|  | len = 2; | 
|  | snprintf(buf, buflen, "%d", val); | 
|  | } | 
|  | break; | 
|  | case VALUE_TYPE_CHAR: | 
|  | { | 
|  | int val; | 
|  | val = tvb_get_ntohs(tvb, ofs); | 
|  | len = 2; | 
|  | /* show printable ASCII */ | 
|  | if (val >= 0x20 && val < 0x7f) { | 
|  | snprintf(buf, buflen, "%d - %c", val, val); | 
|  | } else { | 
|  | snprintf(buf, buflen, "%d (U+%04x)", val, val); | 
|  | } | 
|  | } | 
|  | break; | 
|  | case VALUE_TYPE_INT: | 
|  | { | 
|  | int val; | 
|  | val = tvb_get_ntohl(tvb, ofs); | 
|  | len = 4; | 
|  | snprintf(buf, buflen, "%d", val); | 
|  | } | 
|  | break; | 
|  | case VALUE_TYPE_FLOAT: | 
|  | { | 
|  | float val; | 
|  | val = tvb_get_ntohieee_float(tvb, ofs); | 
|  | len = 4; | 
|  | snprintf(buf, buflen, "%g", val); | 
|  | } | 
|  | break; | 
|  | case VALUE_TYPE_JAVA_OBJECT: | 
|  | { | 
|  | int val; | 
|  | val = tvb_get_ntohl(tvb, ofs); | 
|  | len = 4; | 
|  | snprintf(buf, buflen, "Java Object %d", val); | 
|  | } | 
|  | break; | 
|  | case VALUE_TYPE_JS_OBJECT: | 
|  | { | 
|  | int val; | 
|  | val = tvb_get_ntohl(tvb, ofs); | 
|  | len = 4; | 
|  | snprintf(buf, buflen, "JS Object %d", val); | 
|  | } | 
|  | break; | 
|  | case VALUE_TYPE_LONG: | 
|  | { | 
|  | guint64 val; | 
|  | val = tvb_get_ntoh64(tvb, ofs); | 
|  | len = 8; | 
|  | /* no portable way to print guint64, so do it in two pieces */ | 
|  | snprintf(buf, buflen, "0x%08x%08x", (int) ((val >> 32) & 0xFFFFFFFF), | 
|  | (int) (val & 0xFFFFFFFF)); | 
|  | } | 
|  | break; | 
|  | case VALUE_TYPE_DOUBLE: | 
|  | { | 
|  | double val; | 
|  | val = tvb_get_ntohieee_double(tvb, ofs); | 
|  | len = 8; | 
|  | snprintf(buf, buflen, "%lg", val); | 
|  | } | 
|  | break; | 
|  | case VALUE_TYPE_STRING: | 
|  | { | 
|  | guint8* str; | 
|  | len = tvb_get_ntohl(tvb, ofs); | 
|  | ofs += 4; | 
|  | str = tvb_get_ephemeral_string(tvb, ofs, len); | 
|  | if (len > buflen - 3 && buflen >= 6) { | 
|  | snprintf(buf, buflen, "\"%.*s...\"", buflen - 6, (char*) str); | 
|  | } else { | 
|  | snprintf(buf, buflen, "\"%s\"", (char*) str); | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | /* ensure the buffer is null-terminated */; | 
|  | buf[buflen - 1] = 0; | 
|  |  | 
|  | /* point to byte after this Value */ | 
|  | return ofs + len; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Show a labelled Value. | 
|  | * | 
|  | * hdr - name of this Value | 
|  | * ofs - offset into buffer where the Value tag byte is located. | 
|  | * | 
|  | * returns the offset after the last byte of this Value | 
|  | */ | 
|  | static int showValue(proto_tree* tree, char* hdr, tvbuff_t* tvb, int ofs) { | 
|  | proto_tree* subtree; | 
|  | proto_item* ti; | 
|  | guint8 tag; | 
|  | int newOffset; | 
|  | char buf[40]; | 
|  | *buf = 0; | 
|  | newOffset = getValue(tvb, ofs, buf, sizeof(buf)); | 
|  | tag = tvb_get_guint8(tvb, ofs); | 
|  | ti = proto_tree_add_string_format(tree, hf_gwtcs_val_hdr, tvb, ofs, | 
|  | newOffset - ofs, 0, "%s: %s", hdr, buf); | 
|  | subtree = proto_item_add_subtree(ti, ett_value); | 
|  | proto_tree_add_item(subtree, hf_gwtcs_value_tag, tvb, ofs++, 1, FALSE); | 
|  | switch (tag) { | 
|  | case VALUE_TYPE_NULL: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_null, tvb, ofs, 0, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_UNDEFINED: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_undef, tvb, ofs, 0, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_BOOLEAN: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_bool, tvb, ofs, 1, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_BYTE: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_byte, tvb, ofs, 1, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_CHAR: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_char, tvb, ofs, 2, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_SHORT: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_short, tvb, ofs, 2, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_INT: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_int, tvb, ofs, 4, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_LONG: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_long, tvb, ofs, 8, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_FLOAT: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_float, tvb, ofs, 4, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_DOUBLE: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_double, tvb, ofs, 8, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_STRING: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_string, tvb, ofs, 4, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_JAVA_OBJECT: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_javaobj, tvb, ofs, 4, FALSE); | 
|  | break; | 
|  | case VALUE_TYPE_JS_OBJECT: | 
|  | proto_tree_add_item(subtree, hf_gwtcs_val_jsobj, tvb, ofs, 4, FALSE); | 
|  | break; | 
|  | } | 
|  | return newOffset; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Initialize memchunk system. | 
|  | */ | 
|  | static void init() { | 
|  | if (memChunk) { | 
|  | g_mem_chunk_destroy(memChunk); | 
|  | } | 
|  | memChunk = g_mem_chunk_new("gwtcs data", sizeof(gwtcs_data), | 
|  | 20 * sizeof(gwtcs_data), G_ALLOC_AND_FREE); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Dissect a single packet. | 
|  | */ | 
|  | static int dissect_gwtcs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) | 
|  | { | 
|  | guint8 packetType; | 
|  | conversation_t* conv; | 
|  | gwtcs_data* data = 0; | 
|  | int isClient = 0; | 
|  |  | 
|  | if (tvb_length(tvb) < 1) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | packetType = tvb_get_guint8(tvb, 0); | 
|  | if (packetType > MAX_PACKET_TYPE) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (check_col(pinfo->cinfo, COL_PROTOCOL)) { | 
|  | col_set_str(pinfo->cinfo, COL_PROTOCOL, "GWT-CS"); | 
|  | } | 
|  |  | 
|  | /* Clear the info column */ | 
|  | if (check_col(pinfo->cinfo, COL_INFO)) { | 
|  | col_set_str(pinfo->cinfo, COL_INFO, ""); | 
|  | } | 
|  |  | 
|  | /* get the conversation */ | 
|  | conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, | 
|  | pinfo->ptype, pinfo->srcport, pinfo->destport, 0); | 
|  | if (!conv) { | 
|  | conv = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, | 
|  | pinfo->ptype, pinfo->srcport, pinfo->destport, 0); | 
|  | } | 
|  | data = (gwtcs_data*) conversation_get_proto_data(conv, proto_gwtcs); | 
|  | if (!data) { | 
|  | data = (gwtcs_data*) g_mem_chunk_alloc(memChunk); | 
|  | data->clientPort = -1; | 
|  | data->level = 0; | 
|  | conversation_add_proto_data(conv, proto_gwtcs, data); | 
|  | } | 
|  |  | 
|  | if (packetType == MESSAGE_TYPE_CHECK_VERSIONS) { | 
|  | data->clientAddress = pinfo->src; | 
|  | data->clientPort = pinfo->srcport; | 
|  | } | 
|  |  | 
|  | if (data->clientPort == pinfo->srcport) { | 
|  | isClient = 1; | 
|  | } | 
|  |  | 
|  | /* Set the info column */ | 
|  | if (check_col(pinfo->cinfo,COL_INFO)) { | 
|  | gint32 len; | 
|  | guint8* str; | 
|  | int i; | 
|  | gint32 offset = 1; | 
|  | if (data->clientPort != -1) { | 
|  | col_add_str(pinfo->cinfo, COL_INFO, isClient ? "C->S: " : "S->C: "); | 
|  | } | 
|  | for (i = 0; i < data->level; ++i) { | 
|  | col_append_str(pinfo->cinfo, COL_INFO, " "); | 
|  | } | 
|  | col_append_str(pinfo->cinfo, COL_INFO, packetTypes[packetType].strptr); | 
|  | switch (packetType) { | 
|  | case MESSAGE_TYPE_CHECK_VERSIONS: | 
|  | { | 
|  | int minvers, maxvers; | 
|  | minvers = tvb_get_ntohl(tvb, offset); | 
|  | offset += 4; | 
|  | maxvers = tvb_get_ntohl(tvb, offset); | 
|  | col_append_fstr(pinfo->cinfo, COL_INFO, " vers=%d-%d", minvers, | 
|  | maxvers); | 
|  | } | 
|  | break; | 
|  | case MESSAGE_TYPE_PROTOCOL_VERSION: | 
|  | { | 
|  | int vers; | 
|  | vers = tvb_get_ntohl(tvb, offset); | 
|  | col_append_fstr(pinfo->cinfo, COL_INFO, " vers=%d", vers); | 
|  | } | 
|  | break; | 
|  | case MESSAGE_TYPE_LOAD_MODULE: | 
|  | data->level++; | 
|  | // URL | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | offset += 4 + len; | 
|  | // tab key | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | offset += 4 + len; | 
|  | // session key | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | offset += 4 + len; | 
|  | // module name | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | offset  += 4; | 
|  | // clip string | 
|  | if (len > MAX_STRING_LENGTH) { | 
|  | len = MAX_STRING_LENGTH; | 
|  | } | 
|  | str = tvb_get_ephemeral_string(tvb, offset, len); | 
|  | col_append_fstr(pinfo->cinfo, COL_INFO, " %s", str); | 
|  | break; | 
|  | case MESSAGE_TYPE_INVOKE: | 
|  | data->level++; | 
|  | if (data->clientPort == -1) { | 
|  | break; | 
|  | } | 
|  | if (isClient) { | 
|  | int dispId; | 
|  | dispId = tvb_get_ntohl(tvb, offset); | 
|  | offset += 4; | 
|  | col_append_fstr(pinfo->cinfo, COL_INFO, " dispid=%d", dispId); | 
|  | } else { | 
|  | // module name | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | offset += 4; | 
|  | // clip string | 
|  | if (len > MAX_STRING_LENGTH) { | 
|  | len = MAX_STRING_LENGTH; | 
|  | } | 
|  | str = tvb_get_ephemeral_string(tvb, offset, len); | 
|  | col_append_fstr(pinfo->cinfo, COL_INFO, " %s", str); | 
|  | } | 
|  | break; | 
|  | case MESSAGE_TYPE_RETURN: | 
|  | { | 
|  | char buf[40]; | 
|  | guint8 isexc; | 
|  | data->level--; | 
|  | isexc = tvb_get_guint8(tvb, 1); | 
|  | getValue(tvb, 2, buf, sizeof(buf)); | 
|  | col_append_fstr(pinfo->cinfo, COL_INFO, " %s%s", | 
|  | isexc ? "** EXCEPTION ** " : "", buf); | 
|  | } | 
|  | break; | 
|  | case MESSAGE_TYPE_INVOKESPECIAL: | 
|  | { | 
|  | guint8 specialType; | 
|  | data->level++; | 
|  | specialType = tvb_get_guint8(tvb, 1); | 
|  | col_append_fstr(pinfo->cinfo, COL_INFO, " %s", | 
|  | specialTypes[specialType].strptr); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * If tree is non-null, then we want to get the detailed data. | 
|  | */ | 
|  | if (tree) { | 
|  | proto_item *ti = 0; | 
|  | proto_tree *gwtcs_tree = 0; | 
|  | gint32 offset = 1; | 
|  |  | 
|  | ti = proto_tree_add_item(tree, proto_gwtcs, tvb, 0 , -1, FALSE); | 
|  | gwtcs_tree = proto_item_add_subtree(ti, ett_gwtcs); | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_pdu_type, tvb, 0, 1, FALSE); | 
|  | switch (packetType) { | 
|  | case MESSAGE_TYPE_CHECK_VERSIONS: | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_min_vers, tvb, 1, 4, FALSE); | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_max_vers, tvb, 5, 4, FALSE); | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_hosted_vers, tvb, 9, 4, FALSE); | 
|  | break; | 
|  | case MESSAGE_TYPE_PROTOCOL_VERSION: | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_sel_vers, tvb, 1, 4, FALSE); | 
|  | break; | 
|  | case MESSAGE_TYPE_LOAD_MODULE: | 
|  | { | 
|  | guint32 len; | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_lm_url, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4 + len; | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_lm_tabkey, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4 + len; | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_lm_seskey, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4 + len; | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_lm_modname, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4 + len; | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_lm_ua, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4 + len; | 
|  | } | 
|  | break; | 
|  | case MESSAGE_TYPE_INVOKE: | 
|  | { | 
|  | int numArgs, len, i; | 
|  | proto_item* ti; | 
|  | proto_tree* subtree; | 
|  | if (data->clientPort == -1) { | 
|  | proto_tree_add_text(gwtcs_tree, tvb, 1, -1, | 
|  | "Can't decode - unknown direction"); | 
|  | break; | 
|  | } | 
|  | if (isClient) { | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_dispid, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4; | 
|  | } else { | 
|  | // method name | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_methname, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4 + len; | 
|  | } | 
|  | offset = showValue(gwtcs_tree, "This Value", tvb, offset); | 
|  | numArgs = tvb_get_ntohl(tvb, offset); | 
|  | ti = proto_tree_add_item(gwtcs_tree, hf_gwtcs_numargs, tvb, offset, 4, | 
|  | FALSE); | 
|  | subtree = proto_item_add_subtree(ti, ett_args); | 
|  | offset += 4; | 
|  | for (i = 0; i < numArgs; ++i) { | 
|  | char argName[10]; | 
|  | snprintf(argName, sizeof(argName), "arg%d", i); | 
|  | offset = showValue(subtree, argName, tvb, offset); | 
|  | } | 
|  | } | 
|  | break; | 
|  | case MESSAGE_TYPE_RETURN: | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_isexc, tvb, 1, 1, FALSE); | 
|  | showValue(gwtcs_tree, "Return Value", tvb, 2); | 
|  | break; | 
|  | case MESSAGE_TYPE_LOADJSNI: | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_jsni, tvb, 1, 4, FALSE); | 
|  | break; | 
|  | case MESSAGE_TYPE_INVOKESPECIAL: | 
|  | { | 
|  | int numArgs, i; | 
|  | proto_item* ti; | 
|  | proto_tree* subtree; | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_spectype, tvb, offset++, 1, | 
|  | FALSE); | 
|  | numArgs = tvb_get_ntohl(tvb, offset); | 
|  | ti = proto_tree_add_item(gwtcs_tree, hf_gwtcs_numargs, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4; | 
|  | subtree = proto_item_add_subtree(ti, ett_args); | 
|  | for (i = 0; i < numArgs; ++i) { | 
|  | char argName[10]; | 
|  | snprintf(argName, sizeof(argName), "arg%d", i); | 
|  | offset = showValue(subtree, argName, tvb, offset); | 
|  | } | 
|  | } | 
|  | break; | 
|  | case MESSAGE_TYPE_FREEVALUE: | 
|  | { | 
|  | int numArgs, i, label; | 
|  | proto_item* ti; | 
|  | proto_tree* subtree; | 
|  | numArgs = tvb_get_ntohl(tvb, offset); | 
|  | ti = proto_tree_add_item(gwtcs_tree, hf_gwtcs_numargs, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4; | 
|  | subtree = proto_item_add_subtree(ti, ett_args); | 
|  | label = isClient ? hf_gwtcs_val_jsobj : hf_gwtcs_val_javaobj; | 
|  | for (i = 0; i < numArgs; ++i) { | 
|  | proto_tree_add_item(subtree, label, tvb, offset, 4, FALSE); | 
|  | offset += 4; | 
|  | } | 
|  | } | 
|  | break; | 
|  | case MESSAGE_TYPE_CHOOSE_TRANSPORT: | 
|  | { | 
|  | int numArgs, i, len; | 
|  | proto_item* ti; | 
|  | proto_tree* subtree; | 
|  | numArgs = tvb_get_ntohl(tvb, offset); | 
|  | ti = proto_tree_add_item(gwtcs_tree, hf_gwtcs_numargs, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4; | 
|  | subtree = proto_item_add_subtree(ti, ett_args); | 
|  | for (i = 0; i < numArgs; ++i) { | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | proto_tree_add_item(subtree, hf_gwtcs_transport, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4 + len; | 
|  | } | 
|  | } | 
|  | break; | 
|  | case MESSAGE_TYPE_SWITCH_TRANSPORT: | 
|  | { | 
|  | int len; | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_transport, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4 + len; | 
|  | len = tvb_get_ntohl(tvb, offset); | 
|  | proto_tree_add_item(gwtcs_tree, hf_gwtcs_transargs, tvb, offset, 4, | 
|  | FALSE); | 
|  | offset += 4 + len; | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return tvb_length(tvb); | 
|  | } | 
|  |  | 
|  | void proto_register_gwtcs(void) | 
|  | { | 
|  | /* | 
|  | * List of subtree identifiers to be allocated. | 
|  | */ | 
|  | static gint *ett[] = { | 
|  | &ett_gwtcs, | 
|  | &ett_value, | 
|  | &ett_args, | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * List of display identifiers to be allocated. | 
|  | */ | 
|  | static hf_register_info hf[] = { | 
|  | { | 
|  | &hf_gwtcs_pdu_type, | 
|  | { | 
|  | "Packet Type", "gwtcs.type", | 
|  | FT_UINT8, BASE_DEC, VALS(packetTypes), 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_spectype, | 
|  | { | 
|  | "Type", "gwtcs.spectype", | 
|  | FT_UINT8, BASE_DEC, VALS(specialTypes), 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_value_tag, | 
|  | { | 
|  | "Value Tag", "gwtcs.value.tag", | 
|  | FT_UINT8, BASE_DEC, VALS(valueTypes), 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_min_vers, | 
|  | { | 
|  | "Minimum version", "gwtcs.minvers", | 
|  | FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_max_vers, | 
|  | { | 
|  | "Maximum version", "gwtcs.maxvers", | 
|  | FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_hosted_vers, | 
|  | { | 
|  | "hosted.html version", "gwtcs.hostedvers", | 
|  | FT_UINT_STRING, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_sel_vers, | 
|  | { | 
|  | "Selected version", "gwtcs.selvers", | 
|  | FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_lm_url, | 
|  | { | 
|  | "URL", "gwtcs.lm.url", | 
|  | FT_UINT_STRING, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_lm_modname, | 
|  | { | 
|  | "Module Name", "gwtcs.lm.modname", | 
|  | FT_UINT_STRING, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_lm_tabkey, | 
|  | { | 
|  | "Tab Key", "gwtcs.lm.tabkey", | 
|  | FT_UINT_STRING, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_lm_seskey, | 
|  | { | 
|  | "Session Key", "gwtcs.lm.seskey", | 
|  | FT_UINT_STRING, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_lm_ua, | 
|  | { | 
|  | "User Agent", "gwtcs.lm.ua", | 
|  | FT_UINT_STRING, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_methname, | 
|  | { | 
|  | "Method Name", "gwtcs.lm.methname", | 
|  | FT_UINT_STRING, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_isexc, | 
|  | { | 
|  | "Is Exception", "gwtcs.isexc", | 
|  | FT_BOOLEAN, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_dispid, | 
|  | { | 
|  | "Dispatch ID", "gwtcs.dispid", | 
|  | FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_jsni, | 
|  | { | 
|  | "JSNI Source", "gwtcs.jsni", | 
|  | FT_UINT_STRING, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_hdr, | 
|  | { | 
|  | "Value", "gwtcs.val.hdr", | 
|  | FT_STRINGZ, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_numargs, | 
|  | { | 
|  | "# of Arguments", "gwtcs.val.numargs", | 
|  | FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_null, | 
|  | { | 
|  | "Null Value", "gwtcs.val.null", | 
|  | FT_NONE, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_undef, | 
|  | { | 
|  | "Undef Value", "gwtcs.val.undef", | 
|  | FT_NONE, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_bool, | 
|  | { | 
|  | "Boolean Value", "gwtcs.val.bool", | 
|  | FT_BOOLEAN, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_byte, | 
|  | { | 
|  | "Byte Value", "gwtcs.val.byte", | 
|  | FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_char, | 
|  | { | 
|  | "Char Value", "gwtcs.val.char", | 
|  | FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_short, | 
|  | { | 
|  | "Short Value", "gwtcs.val.short", | 
|  | FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_int, | 
|  | { | 
|  | "Int Value", "gwtcs.val.int", | 
|  | FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_long, | 
|  | { | 
|  | "Long Value", "gwtcs.val.long", | 
|  | FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_float, | 
|  | { | 
|  | "Float Value", "gwtcs.val.float", | 
|  | FT_FLOAT, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_double, | 
|  | { | 
|  | "Double Value", "gwtcs.val.double", | 
|  | FT_DOUBLE, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_javaobj, | 
|  | { | 
|  | "Java Object Id", "gwtcs.val.javaobj", | 
|  | FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_jsobj, | 
|  | { | 
|  | "JS Object Id", "gwtcs.val.jsobj", | 
|  | FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_val_string, | 
|  | { | 
|  | "String Value", "gwtcs.val.string", | 
|  | FT_UINT_STRING, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_transport, | 
|  | { | 
|  | "Transport Name", "gwtcs.transport", | 
|  | FT_UINT_STRING, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | { | 
|  | &hf_gwtcs_transargs, | 
|  | { | 
|  | "Transport Args", "gwtcs.transargs", | 
|  | FT_UINT_STRING, BASE_DEC, NULL, 0x0, NULL, HFILL, | 
|  | } | 
|  | }, | 
|  | }; | 
|  |  | 
|  | if (proto_gwtcs == -1) | 
|  | { | 
|  | register_init_routine(&init); | 
|  | proto_gwtcs = proto_register_protocol ( | 
|  | "GWT Code Server Protocol", /* name */ | 
|  | "GWT-CS",          /* short name */ | 
|  | "gwtcs"           /* abbrev */ | 
|  | ); | 
|  |  | 
|  | proto_register_field_array(proto_gwtcs, hf, array_length(hf)); | 
|  | proto_register_subtree_array(ett, array_length(ett)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void proto_reg_handoff_gwtcs(void) | 
|  | { | 
|  | static int Initialized=FALSE; | 
|  |  | 
|  | /* register with wireshark to dissect tdp packets on port 9997 */ | 
|  | if (!Initialized) { | 
|  | gwtcs_handle = new_create_dissector_handle(dissect_gwtcs, proto_gwtcs); | 
|  | dissector_add("tcp.port", DEFAULT_GWTCS_PORT, gwtcs_handle); | 
|  | Initialized = TRUE; | 
|  | } | 
|  | } |