/* packet-edonkey.c * Routines for edonkey dissection * Copyright 2003, Xuan Zhang * eDonkey dissector based on protocol descriptions from mldonkey: * http://savannah.nongnu.org/download/mldonkey/docs/Edonkey-Overnet/edonkey-protocol.txt * http://savannah.nongnu.org/download/mldonkey/docs/Edonkey-Overnet/overnet-protocol.txt * * $Id: packet-edonkey.c,v 1.1 2003/07/16 21:13:48 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "packet-edonkey.h" static int proto_edonkey = -1; static int hf_edonkey_message = -1; static int hf_edonkey_protocol = -1; static int hf_edonkey_message_length = -1; static int hf_edonkey_message_type = -1; static int hf_edonkey_client_hash = -1; static int hf_edonkey_server_hash = -1; static int hf_edonkey_file_hash = -1; static int hf_edonkey_client_id = -1; static int hf_edonkey_metatag_namesize = -1; static int hf_edonkey_metatag_type = -1; static int hf_edonkey_metatag = -1; static int hf_edonkey_metatag_name = -1; static int hf_edonkey_metatag_id = -1; static int hf_edonkey_search = -1; static int hf_edonkey_ip = -1; static int hf_edonkey_port = -1; static int hf_edonkey_hash = -1; static int hf_edonkey_directory = -1; static int hf_edonkey_string = -1; static int hf_edonkey_string_length = -1; static int hf_edonkey_fileinfo = -1; static int hf_edonkey_clientinfo = -1; static int hf_edonkey_serverinfo = -1; static int hf_overnet_peer = -1; static gint ett_edonkey = -1; static gint ett_edonkey_message = -1; static gint ett_edonkey_metatag = -1; static gint ett_edonkey_search = -1; static gint ett_edonkey_fileinfo = -1; static gint ett_edonkey_serverinfo = -1; static gint ett_edonkey_clientinfo = -1; static gint ett_overnet_peer = -1; static const value_string edonkey_protocols[] = { { EDONKEY_PROTO_EDONKEY, "eDonkey" }, { EDONKEY_PROTO_EMULE_EXT, "eMule Extensions" }, { EDONKEY_PROTO_EMULE_COMP, "eMule Compressed" }, { 0, NULL } }; static const value_string edonkey_tcp_msgs[] = { { EDONKEY_MSG_HELLO, "Hello" }, { EDONKEY_MSG_BAD_PROTO, "Bad Proto" }, { EDONKEY_MSG_GET_SERVER_LIST, "Get Server List" }, { EDONKEY_MSG_OFFER_FILES, "Offer Files" }, { EDONKEY_MSG_SEARCH_FILES, "Search Files" }, { EDONKEY_MSG_DISCONNECT, "Disconnect" }, { EDONKEY_MSG_GET_SOURCES, "Get Sources" }, { EDONKEY_MSG_SEARCH_USER, "Search User" }, { EDONKEY_MSG_CLIENT_CB_REQ, "Client Callback Request" }, { EDONKEY_MSG_MORE_RESULTS, "More Results" }, { EDONKEY_MSG_SERVER_LIST, "Server List" }, { EDONKEY_MSG_SEARCH_FILE_RESULTS, "Search File Results" }, { EDONKEY_MSG_SERVER_STATUS, "Server Status" }, { EDONKEY_MSG_SERVER_CB_REQ, "Server Callback Request" }, { EDONKEY_MSG_CALLBACK_FAIL, "Callback Fail" }, { EDONKEY_MSG_SERVER_MESSAGE, "Server Message" }, { EDONKEY_MSG_ID_CHANGE, "ID Change" }, { EDONKEY_MSG_SERVER_INFO_DATA, "Server Info Data" }, { EDONKEY_MSG_FOUND_SOURCES, "Found Sources" }, { EDONKEY_MSG_SEARCH_USER_RESULTS, "Search User Results" }, { EDONKEY_MSG_SENDING_PART, "Sending Part" }, { EDONKEY_MSG_REQUEST_PARTS, "Request Parts" }, { EDONKEY_MSG_NO_SUCH_FILE, "No Such File" }, { EDONKEY_MSG_END_OF_DOWNLOAD, "End of Download" }, { EDONKEY_MSG_VIEW_FILES, "View Files" }, { EDONKEY_MSG_VIEW_FILES_ANSWER, "View Files Answer" }, { EDONKEY_MSG_HELLO_ANSWER, "Hello Answer" }, { EDONKEY_MSG_NEW_CLIENT_ID, "New Client ID" }, { EDONKEY_MSG_CLIENT_MESSAGE, "Client Message" }, { EDONKEY_MSG_FILE_STATUS_REQUEST, "File Status Request" }, { EDONKEY_MSG_FILE_STATUS, "File Status" }, { EDONKEY_MSG_HASHSET_REQUEST, "Hashset Request" }, { EDONKEY_MSG_HASHSET_ANSWER, "Hashset Answer" }, { EDONKEY_MSG_SLOT_REQUEST, "Slot Request" }, { EDONKEY_MSG_SLOT_GIVEN, "Slot Given" }, { EDONKEY_MSG_SLOT_RELEASE, "Slot Release" }, { EDONKEY_MSG_SLOT_TAKEN, "Slot Taken" }, { EDONKEY_MSG_FILE_REQUEST, "File Request" }, { EDONKEY_MSG_FILE_REQUEST_ANSWER, "File Request Answer" }, { EDONKEY_MSG_GET_SHARED_DIRS, "Get Shared Directories" }, { EDONKEY_MSG_GET_SHARED_FILES, "Get Shared Files" }, { EDONKEY_MSG_SHARED_DIRS, "Shared Directores" }, { EDONKEY_MSG_SHARED_FILES, "Shared Files" }, { EDONKEY_MSG_SHARED_DENIED, "Shared Denied" }, { 0, NULL } }; static const value_string emule_tcp_msgs[] = { { EMULE_MSG_HELLO, "Hello" }, { EMULE_MSG_HELLO_ANSWER, "Hello Answer" }, { EMULE_MSG_DATA_COMPRESSED, "Data Compressed" }, { EMULE_MSG_QUEUE_RANKING, "Queue Ranking" }, { EMULE_MSG_SOURCES_REQUEST, "Sources Request" }, { EMULE_MSG_SOURCES_ANSWER, "Sources Answer" }, { 0, NULL } }; static const value_string edonkey_udp_msgs[] = { { EDONKEY_MSG_UDP_SERVER_STATUS_REQUEST, "Server Status Request" }, { EDONKEY_MSG_UDP_SERVER_STATUS, "Server Status" }, { EDONKEY_MSG_UDP_SEARCH_FILE, "Search File" }, { EDONKEY_MSG_UDP_SEARCH_FILE_RESULTS, "Search File Results" }, { EDONKEY_MSG_UDP_GET_SOURCES, "Get Sources" }, { EDONKEY_MSG_UDP_FOUND_SOURCES, "Found Sources" }, { EDONKEY_MSG_UDP_CALLBACK_REQUEST, "Callback Request" }, { EDONKEY_MSG_UDP_CALLBACK_FAIL, "Callback Fail" }, { EDONKEY_MSG_UDP_SERVER_LIST, "Server List" }, { EDONKEY_MSG_UDP_GET_SERVER_INFO, "Get Server Info" }, { EDONKEY_MSG_UDP_SERVER_INFO, "Server Info" }, { EDONKEY_MSG_UDP_GET_SERVER_LIST, "Get Server List" }, /* eMule Extensions */ { EMULE_MSG_UDP_REASKFILEPING, "Reask File Ping" }, { EMULE_MSG_UDP_REASKACK, "Reask ACK" }, { EMULE_MSG_UDP_FILE_NOT_FOUND, "File not found" }, { EMULE_MSG_UDP_QUEUE_FULL, "Queue Full" }, /* Overnet Extensions */ { OVERNET_MSG_UDP_CONNECT, "Connect" }, { OVERNET_MSG_UDP_CONNECT_REPLY, "Connect Reply" }, { OVERNET_MSG_UDP_PUBLICIZE, "Publicize" }, { OVERNET_MSG_UDP_PUBLICIZE_ACK, "Publicize ACK" }, { OVERNET_MSG_UDP_SEARCH, "Search" }, { OVERNET_MSG_UDP_SEARCH_NEXT, "Search Next" }, { OVERNET_MSG_UDP_SEARCH_INFO, "Search Info" }, { OVERNET_MSG_UDP_SEARCH_RESULT, "Search Result" }, { OVERNET_MSG_UDP_SEARCH_END, "Search End" }, { OVERNET_MSG_UDP_PUBLISH, "Publish" }, { OVERNET_MSG_UDP_PUBLISH_ACK, "Publish ACK" }, { OVERNET_MSG_UDP_IDENTIFY_REPLY, "Identify Reply" }, { OVERNET_MSG_UDP_IDENTIFY_ACK, "Identify ACK" }, { OVERNET_MSG_UDP_FIREWALL_CONNECTION, "Firewall Connection" }, { OVERNET_MSG_UDP_FIREWALL_CONNECTION_ACK, "Firewall Connection ACK" }, { OVERNET_MSG_UDP_FIREWALL_CONNECTION_NACK, "Firewall Connection NACK" }, { OVERNET_MSG_UDP_IP_QUERY, "IP Query" }, { OVERNET_MSG_UDP_IP_QUERY_ANSWER, "IP Query Answer" }, { OVERNET_MSG_UDP_IP_QUERY_END, "IP Query End" }, { OVERNET_MSG_UDP_IDENTIFY, "Identify" }, { 0, NULL } }; static const value_string edonkey_special_tags[] = { { EDONKEY_STAG_NAME, "Name" }, { EDONKEY_STAG_SIZE, "Size" }, { EDONKEY_STAG_TYPE, "Type" }, { EDONKEY_STAG_FORMAT, "Format" }, { EDONKEY_STAG_COLLECTION, "Collection" }, { EDONKEY_STAG_PART_PATH, "Part Path" }, { EDONKEY_STAG_PART_HASH, "Part Hash" }, { EDONKEY_STAG_COPIED, "Copied" }, { EDONKEY_STAG_GAP_START, "Gap Start" }, { EDONKEY_STAG_GAP_END, "Gap End" }, { EDONKEY_STAG_DESCRIPTION, "Description" }, { EDONKEY_STAG_PING, "Ping" }, { EDONKEY_STAG_FAIL, "Fail" }, { EDONKEY_STAG_PREFERENCE, "Preference" }, { EDONKEY_STAG_PORT, "Port" }, { EDONKEY_STAG_IP, "IP" }, { EDONKEY_STAG_VERSION, "Version" }, { EDONKEY_STAG_TEMPFILE, "Temporary File" }, { EDONKEY_STAG_PRIORITY, "Priority" }, { EDONKEY_STAG_STATUS, "Status" }, { EDONKEY_STAG_AVAILABILITY, "Availability" }, { EDONKEY_STAG_QTIME, "Queue Time" }, { EDONKEY_STAG_PARTS, "Parts" }, { EMULE_STAG_COMPRESSION, "Compression" }, { EMULE_STAG_UDP_CLIENT_PORT, "UDP Client Port" }, { EMULE_STAG_UDP_VERSION, "UDP Version" }, { EMULE_STAG_SOURCE_EXCHANGE, "Source Exchange" }, { EMULE_STAG_COMMENTS, "Comments" }, { EMULE_STAG_EXTENDED_REQUEST, "Extended Request" }, { EMULE_STAG_COMPATIBLE_CLIENT, "Compatible Client" }, { 0, NULL } }; static const value_string edonkey_search_ops[] = { { EDONKEY_SEARCH_AND, "AND" }, { EDONKEY_SEARCH_OR, "OR" }, { EDONKEY_SEARCH_ANDNOT, "AND NOT" }, { 0, NULL } }; static const value_string edonkey_search_conds[] = { { EDONKEY_SEARCH_MIN, "MIN" }, { EDONKEY_SEARCH_MAX, "MAX" }, { 0, NULL } }; /* Dissects a generic eDonkey list */ static int dissect_edonkey_list(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree, int listnum_length, char* listdesc, int (*item_dissector)(tvbuff_t *, packet_info *, int, proto_tree *)) { /* ::= * */ guint32 listnum, i; switch (listnum_length) { case 1: listnum = tvb_get_guint8(tvb, offset); break; case 2: listnum = tvb_get_letohs(tvb, offset); break; case 4: listnum = tvb_get_letohl(tvb, offset); break; default: /* Not Supported */ return offset; } proto_tree_add_text(tree, tvb, offset, listnum_length, "%s List Size: %u", listdesc, listnum); offset+=listnum_length; for (i=0; i ::= */ /* ::= || */ proto_item *ti; proto_tree *metatag_tree; guint8 tag_type, special_tagtype; guint16 tag_name_size, string_length; guint32 tag_length, tag_value_guint32; int tag_offset; tag_type = tvb_get_guint8(tvb, offset); tag_name_size = tvb_get_letohs(tvb, offset+1); special_tagtype = tvb_get_guint8(tvb, offset+3); tag_length = 3 + tag_name_size; tag_offset = offset + tag_length; switch (tag_type) { case EDONKEY_MTAG_HASH: /* ::= HASH */ tag_length += 16; ti = proto_tree_add_item(tree, hf_edonkey_metatag, tvb, offset, tag_length, FALSE); metatag_tree = proto_item_add_subtree(ti, ett_edonkey_metatag); proto_tree_add_uint(metatag_tree, hf_edonkey_metatag_type, tvb, offset, 1, tag_type); proto_tree_add_uint(metatag_tree, hf_edonkey_metatag_namesize, tvb, offset+1, 2, tag_name_size); edonkey_tree_add_metatag_name(metatag_tree, tvb, offset+3, tag_name_size, special_tagtype); proto_tree_add_item(metatag_tree, hf_edonkey_hash, tvb, tag_offset, 16, FALSE); break; case EDONKEY_MTAG_STRING: /* ::= */ string_length = tvb_get_letohs(tvb, tag_offset); tag_length += 2+string_length; ti = proto_tree_add_item(tree, hf_edonkey_metatag, tvb, offset, tag_length, FALSE); metatag_tree = proto_item_add_subtree(ti, ett_edonkey_metatag); proto_tree_add_uint(metatag_tree, hf_edonkey_metatag_type, tvb, offset, 1, tag_type); proto_tree_add_uint(metatag_tree, hf_edonkey_metatag_namesize, tvb, offset+1, 2, tag_name_size); edonkey_tree_add_metatag_name(metatag_tree, tvb, offset+3, tag_name_size, special_tagtype); proto_tree_add_uint(metatag_tree, hf_edonkey_string_length, tvb, tag_offset, 2, string_length); proto_tree_add_item(metatag_tree, hf_edonkey_string, tvb, tag_offset+2, string_length, FALSE); break; case EDONKEY_MTAG_DWORD: /* ::= guint32 */ tag_length += 4; ti = proto_tree_add_item(tree, hf_edonkey_metatag, tvb, offset, tag_length, FALSE); metatag_tree = proto_item_add_subtree(ti, ett_edonkey_metatag); proto_tree_add_uint(metatag_tree, hf_edonkey_metatag_type, tvb, offset, 1, tag_type); proto_tree_add_uint(metatag_tree, hf_edonkey_metatag_namesize, tvb, offset+1, 2, tag_name_size); edonkey_tree_add_metatag_name(metatag_tree, tvb, offset+3, tag_name_size, special_tagtype); if (edonkey_metatag_name_get_type(tvb, offset+3, tag_name_size, special_tagtype) == EDONKEY_STAG_IP) { proto_tree_add_item(metatag_tree, hf_edonkey_ip, tvb, tag_offset, 4, FALSE); } else { tag_value_guint32 = tvb_get_letohl(tvb, tag_offset); proto_tree_add_text(metatag_tree, tvb, tag_offset, 4, "Meta Tag Value: %u", tag_value_guint32); } break; case EDONKEY_MTAG_FLOAT: /* ::= 4 byte float */ tag_length += 4; ti = proto_tree_add_item(tree, hf_edonkey_metatag, tvb, offset, tag_length, FALSE); metatag_tree = proto_item_add_subtree(ti, ett_edonkey_metatag); proto_tree_add_uint(metatag_tree, hf_edonkey_metatag_type, tvb, offset, 1, tag_type); proto_tree_add_uint(metatag_tree, hf_edonkey_metatag_namesize, tvb, offset+1, 2, tag_name_size); edonkey_tree_add_metatag_name(metatag_tree, tvb, offset+3, tag_name_size, special_tagtype); break; case EDONKEY_MTAG_BOOL: /* ::= Boolean ?? bytes*/ case EDONKEY_MTAG_BOOL_ARRAY: /* ::= ?? */ case EDONKEY_MTAG_BLOB: /* ::= ?? */ case EDONKEY_MTAG_UNKNOWN: default: /* Unknown tag type - actual tag length is also unknown */ ti = proto_tree_add_item(tree, hf_edonkey_metatag, tvb, offset, tag_length, FALSE); metatag_tree = proto_item_add_subtree(ti, ett_edonkey_metatag); proto_tree_add_text(metatag_tree, tvb, offset, 1, "Unknown Meta Tag Type (0x%02x)", tag_type); proto_tree_add_uint(metatag_tree, hf_edonkey_metatag_namesize, tvb, offset+1, 2, tag_name_size); edonkey_tree_add_metatag_name(metatag_tree, tvb, offset+3, tag_name_size, special_tagtype); break; } return offset + tag_length; } /* Dissects the eDonkey address */ static int dissect_edonkey_address(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /*
::= */ /* guint32 ip = tvb_get_letohl(tvb, offset); proto_tree_add_ipv4(tree, hf_edonkey_ip, tvb, offset, 4, ip); */ proto_tree_add_item(tree, hf_edonkey_ip, tvb, offset, 4, FALSE); proto_tree_add_item(tree, hf_edonkey_port, tvb, offset+4, 2, TRUE); return offset+6; } /* Dissects the eDonkey address list */ static int dissect_edonkey_address_list(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /*
::=
* */ return dissect_edonkey_list(tvb, pinfo, offset, tree, 1, "Address", dissect_edonkey_address); } /* Dissects the eMule address list */ static int dissect_emule_address_list(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /*
::=
* */ return dissect_edonkey_list(tvb, pinfo, offset, tree, 2, "Address", dissect_edonkey_address); } /* Dissects the eDonkey hash */ static int dissect_edonkey_hash(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= HASH (16 word MD4 digest) */ proto_tree_add_item(tree, hf_edonkey_hash, tvb, offset, 16, FALSE); return offset+16; } /* Dissects the eDonkey hash list */ static int dissect_edonkey_hash_list(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= * */ return dissect_edonkey_list(tvb, pinfo, offset, tree, 2, "Hash", dissect_edonkey_hash); } /* Dissects the eDonkey meta tag list */ static int dissect_edonkey_metatag_list(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= * */ return dissect_edonkey_list(tvb, pinfo, offset, tree, 4, "Meta Tag", dissect_edonkey_metatag); } /* Dissects the eDonkey String */ static int dissect_edonkey_string(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= DATA */ guint16 string_length = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_edonkey_string_length, tvb, offset, 2, string_length); proto_tree_add_item(tree, hf_edonkey_string, tvb, offset+2, string_length, FALSE); return offset+2+string_length; } /* Dissects the eDonkey Directory */ static int dissect_edonkey_directory(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= */ guint16 string_length = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_edonkey_string_length, tvb, offset, 2, string_length); proto_tree_add_item(tree, hf_edonkey_directory, tvb, offset+2, string_length, FALSE); return offset+2+string_length; } /* Dissects the eDonkey Filename */ static int dissect_edonkey_file_name(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= */ return dissect_edonkey_string(tvb, pinfo, offset, tree); } /* Dissects the eDonkey directory list */ static int dissect_edonkey_directory_list(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= * */ return dissect_edonkey_list(tvb, pinfo, offset, tree, 4, "Directory", dissect_edonkey_directory); } /* Dissects the eDonkey file hash */ static int dissect_edonkey_file_hash(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= HASH (16 word MD4 digest) */ proto_tree_add_item(tree, hf_edonkey_file_hash, tvb, offset, 16, FALSE); return offset+16; } /* Dissects the eDonkey server hash */ static int dissect_edonkey_server_hash(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= HASH (16 word MD4 digest) */ proto_tree_add_item(tree, hf_edonkey_server_hash, tvb, offset, 16, FALSE); return offset+16; } /* Dissects the eDonkey client hash */ static int dissect_edonkey_client_hash(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= HASH (16 word MD4 digest) */ proto_tree_add_item(tree, hf_edonkey_client_hash, tvb, offset, 16, FALSE); return offset+16; } /* Dissects the eDonkey client ID */ static int dissect_edonkey_client_id(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= guint32 */ /* guint32 ip = tvb_get_letohl(tvb, offset); proto_tree_add_ipv4(tree, hf_edonkey_client_id, tvb, offset, 4, ip); */ proto_tree_add_item(tree, hf_edonkey_client_id, tvb, offset, 4, FALSE); return offset+4; } /* Dissects the eDonkey port */ static int dissect_edonkey_port(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= guint16 */ proto_tree_add_item(tree, hf_edonkey_port, tvb, offset, 2, TRUE); return offset+2; } /* Dissects the eDonkey start offset */ static int dissect_edonkey_start_offset(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= guint32 */ guint32 start = tvb_get_letohl(tvb, offset); proto_tree_add_text(tree, tvb, offset, 4, "Start Offset: %u", start); return offset+4; } /* Dissects the eDonkey end offset */ static int dissect_edonkey_end_offset(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= guint32 */ guint32 end = tvb_get_letohl(tvb, offset); proto_tree_add_text(tree, tvb, offset, 4, "End Offset: %u", end); return offset+4; } /* Dissects the eDonkey client info */ static int dissect_edonkey_client_info(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= */ proto_item *ti; proto_tree *clientinfo_tree; /* Add subtree for client info */ ti = proto_tree_add_item(tree, hf_edonkey_clientinfo, tvb, offset, 0, FALSE); clientinfo_tree = proto_item_add_subtree(ti, ett_edonkey_clientinfo); offset = dissect_edonkey_client_hash(tvb, pinfo, offset, clientinfo_tree); offset = dissect_edonkey_client_id(tvb, pinfo, offset, clientinfo_tree); offset = dissect_edonkey_port(tvb, pinfo, offset, clientinfo_tree); offset = dissect_edonkey_metatag_list(tvb, pinfo, offset, clientinfo_tree); return offset; } /* Dissects the eDonkey client info list */ static int dissect_edonkey_client_info_list(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= * */ return dissect_edonkey_list(tvb, pinfo, offset, tree, 4, "Client Info", dissect_edonkey_client_info); } /* Dissects the eDonkey server info */ static int dissect_edonkey_server_info(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= */ proto_item *ti; proto_tree *serverinfo_tree; /* Add subtree for server info */ ti = proto_tree_add_item(tree, hf_edonkey_serverinfo, tvb, offset, 0, FALSE); serverinfo_tree = proto_item_add_subtree(ti, ett_edonkey_serverinfo); offset = dissect_edonkey_server_hash(tvb, pinfo, offset, serverinfo_tree); offset = dissect_edonkey_address(tvb, pinfo, offset, serverinfo_tree); offset = dissect_edonkey_metatag_list(tvb, pinfo, offset, serverinfo_tree); return offset; } /* Dissects the eDonkey file info */ static int dissect_edonkey_file_info(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= */ proto_item *ti; proto_tree *fileinfo_tree; /* Add subtree for file info */ ti = proto_tree_add_item(tree, hf_edonkey_fileinfo, tvb, offset, 0, FALSE); fileinfo_tree = proto_item_add_subtree(ti, ett_edonkey_fileinfo); offset = dissect_edonkey_file_hash(tvb, pinfo, offset, fileinfo_tree); offset = dissect_edonkey_client_id(tvb, pinfo, offset, fileinfo_tree); offset = dissect_edonkey_port(tvb, pinfo, offset, fileinfo_tree); offset = dissect_edonkey_metatag_list(tvb, pinfo, offset, fileinfo_tree); return offset; } /* Dissects the eDonkey file info list */ static int dissect_edonkey_file_info_list(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= * */ return dissect_edonkey_list(tvb, pinfo, offset, tree, 4, "File Info", dissect_edonkey_file_info); } /* Dissects the Overnet peer type */ static int dissect_overnet_peertype(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= guint8 */ guint8 peertype = tvb_get_guint8(tvb, offset); proto_tree_add_text(tree, tvb, offset, 1, "Peer Type: %u", peertype); return offset+1; } /* Dissects the Overnet peer */ static int dissect_overnet_peer(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::=
*/ proto_item *ti; proto_tree *peer_tree; ti = proto_tree_add_item(tree, hf_overnet_peer, tvb, offset, 16 + 6 + 1, FALSE); peer_tree = proto_item_add_subtree(ti, ett_overnet_peer); offset = dissect_edonkey_hash(tvb, pinfo, offset, peer_tree); offset = dissect_edonkey_address(tvb, pinfo, offset, peer_tree); offset = dissect_overnet_peertype(tvb, pinfo, offset, peer_tree); return offset; } /* Dissects the eDonkey search query */ static int dissect_edonkey_search_query(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) { /* ::= */ proto_item *ti; proto_tree *search_tree; guint8 search_type, operator, special_tagtype, limit_type; guint16 tag_name_size, string_length; guint32 search_length, limit; int string_offset, tag_name_offset; search_type = tvb_get_guint8(tvb, offset); search_length = 1; switch (search_type) { case EDONKEY_SEARCH_BOOL: /* ::= */ search_length += 1; operator = tvb_get_guint8(tvb, offset+1); /* Add subtree for search entry */ ti = proto_tree_add_item(tree, hf_edonkey_search, tvb, offset, search_length, FALSE); search_tree = proto_item_add_subtree(ti, ett_edonkey_search); /* Add query info */ proto_tree_add_text(search_tree, tvb, offset, 2, "Boolean search (0x%02x): %s (0x%02x)", search_type, val_to_str(operator, edonkey_search_ops, "Unknown"), operator); offset+=2; offset = dissect_edonkey_search_query(tvb, pinfo, offset, search_tree); offset = dissect_edonkey_search_query(tvb, pinfo, offset, search_tree); break; case EDONKEY_SEARCH_NAME: /* ::= */ string_offset = offset + search_length; string_length = tvb_get_letohs(tvb, string_offset); search_length += 2+string_length; /* Add subtree for search entry */ ti = proto_tree_add_item(tree, hf_edonkey_search, tvb, offset, search_length, FALSE); search_tree = proto_item_add_subtree(ti, ett_edonkey_search); /* Add query info */ proto_tree_add_text(search_tree, tvb, offset, 1, "Search by name (0x%02x)", search_type); proto_tree_add_uint(search_tree, hf_edonkey_string_length, tvb, string_offset, 2, string_length); proto_tree_add_item(search_tree, hf_edonkey_string, tvb, string_offset+2, string_length, FALSE); offset += search_length; break; case EDONKEY_SEARCH_META: /* ::= */ string_offset = offset + search_length; string_length = tvb_get_letohs(tvb, offset+1); search_length += 2+string_length; tag_name_offset = offset + search_length; tag_name_size = tvb_get_letohs(tvb, tag_name_offset); special_tagtype = tvb_get_guint8(tvb, tag_name_offset+2); search_length += 2 + tag_name_size; /* Add subtree for search entry */ ti = proto_tree_add_item(tree, hf_edonkey_search, tvb, offset, search_length, FALSE); search_tree = proto_item_add_subtree(ti, ett_edonkey_search); /* Add query info */ proto_tree_add_text(search_tree, tvb, offset, 1, "Search by metadata (0x%02x)", search_type); proto_tree_add_uint(search_tree, hf_edonkey_string_length, tvb, string_offset, 2, string_length); proto_tree_add_item(search_tree, hf_edonkey_string, tvb, string_offset+2, string_length, FALSE); proto_tree_add_uint(search_tree, hf_edonkey_metatag_namesize, tvb, tag_name_offset, 2, tag_name_size); edonkey_tree_add_metatag_name(search_tree, tvb, tag_name_offset+2, tag_name_size, special_tagtype); offset += search_length; break; case EDONKEY_SEARCH_LIMIT: /* ::= */ search_length += 5; /* 4 bytes for the limit, one for the minmax */ limit = tvb_get_letohl(tvb, offset+1); limit_type = tvb_get_guint8(tvb, offset+5); tag_name_offset = offset + search_length; tag_name_size = tvb_get_letohs(tvb, tag_name_offset); special_tagtype = tvb_get_guint8(tvb, tag_name_offset+2); search_length += 2 + tag_name_size; /* Add subtree for search entry */ ti = proto_tree_add_item(tree, hf_edonkey_search, tvb, offset, search_length, FALSE); search_tree = proto_item_add_subtree(ti, ett_edonkey_search); /* Add query info */ proto_tree_add_text(search_tree, tvb, offset, 6, "Search by limit (0x%02x): %s %u", search_type, val_to_str(limit_type, edonkey_search_conds, "Unknown"), limit); proto_tree_add_uint(search_tree, hf_edonkey_metatag_namesize, tvb, tag_name_offset, 2, tag_name_size); edonkey_tree_add_metatag_name(search_tree, tvb, tag_name_offset+2, tag_name_size, special_tagtype); offset += search_length; break; default: /* Unknown search type - actual search length is also unknown */ ti = proto_tree_add_item(tree, hf_edonkey_search, tvb, offset, search_length, FALSE); search_tree = proto_item_add_subtree(ti, ett_edonkey_search); proto_tree_add_text(search_tree, tvb, offset, search_length, "Unknown Search (0x%02x)", search_type); offset += search_length; break; } return offset; } static void dissect_edonkey_tcp_message(guint8 msg_type, tvbuff_t *tvb, packet_info *pinfo _U_, int offset, int length, proto_tree *tree) { int msg_start, msg_end, bytes_remaining; guint8 hello, more; guint32 nusers, nfiles; if (tree == NULL) return; bytes_remaining = tvb_reported_length_remaining(tvb, offset); if ((length < 0) || (length > bytes_remaining)) length = bytes_remaining; if (length <= 0) return; msg_start = offset; msg_end = offset + length; switch (msg_type) { case EDONKEY_MSG_HELLO: /* Client to Server: */ /* Client to Client: 0x10 */ hello = tvb_get_guint8(tvb, offset); if (hello == 0x10) /* Hello Client */ offset += 1; offset = dissect_edonkey_client_info(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_HELLO_ANSWER: /* Hello Answer: */ offset = dissect_edonkey_client_info(tvb, pinfo, offset, tree); offset = dissect_edonkey_address(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_SERVER_CB_REQ: /* Server Callback Request: */ offset = dissect_edonkey_address(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_SERVER_INFO_DATA: /* Server Info Data: */ offset = dissect_edonkey_server_info(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_SERVER_LIST: /* Server List:
*/ offset = dissect_edonkey_address_list(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_OFFER_FILES: /* Offer Files: */ case EDONKEY_MSG_VIEW_FILES_ANSWER: /* View Files Answer: */ offset = dissect_edonkey_file_info_list(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_SEARCH_FILE_RESULTS: /* Search File Results: */ offset = dissect_edonkey_file_info_list(tvb, pinfo, offset, tree); more = tvb_get_guint8(tvb, offset); if (more) proto_tree_add_text(tree, tvb, offset, 1, "More: TRUE (0x%02x)", more); else proto_tree_add_text(tree, tvb, offset, 1, "More: FALSE (0x%02x)", more); break; case EDONKEY_MSG_SEARCH_FILES: /* Search File: */ case EDONKEY_MSG_SEARCH_USER: /* Search User: */ offset = dissect_edonkey_search_query(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_GET_SOURCES: /* Get Sources: */ case EDONKEY_MSG_NO_SUCH_FILE: /* No Such File: */ case EDONKEY_MSG_END_OF_DOWNLOAD: /* End of Download: */ case EDONKEY_MSG_FILE_STATUS_REQUEST: /* File Status Request: */ case EDONKEY_MSG_HASHSET_REQUEST: /* Hashset Request: */ case EDONKEY_MSG_SLOT_REQUEST: /* Slot Request: */ case EDONKEY_MSG_FILE_REQUEST: /* File Request: */ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_FOUND_SOURCES: /* Found Sources:
*/ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); offset = dissect_edonkey_address_list(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_CLIENT_CB_REQ: /* Client Callback Request: */ case EDONKEY_MSG_CALLBACK_FAIL: /* Callback Fail: */ case EDONKEY_MSG_ID_CHANGE: /* ID Change: */ offset = dissect_edonkey_client_id(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_NEW_CLIENT_ID: /* New Client ID: */ offset = dissect_edonkey_client_id(tvb, pinfo, offset, tree); offset = dissect_edonkey_client_id(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_SERVER_MESSAGE: /* Server Message: */ case EDONKEY_MSG_CLIENT_MESSAGE: /* Client Message: */ offset = dissect_edonkey_string(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_SERVER_STATUS: /* Server Status: */ nusers = tvb_get_letohl(tvb, offset); nfiles = tvb_get_letohl(tvb, offset+4); proto_tree_add_text(tree, tvb, offset, 4, "Number of Users: %u", nusers); proto_tree_add_text(tree, tvb, offset+4, 4, "Number of Files: %u", nfiles); break; case EDONKEY_MSG_FILE_REQUEST_ANSWER: /* File Request Answer: */ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); offset = dissect_edonkey_file_name(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_REQUEST_PARTS: /* Request Parts: (3) (3) */ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); offset = dissect_edonkey_start_offset(tvb, pinfo, offset, tree); offset = dissect_edonkey_start_offset(tvb, pinfo, offset, tree); offset = dissect_edonkey_start_offset(tvb, pinfo, offset, tree); offset = dissect_edonkey_end_offset(tvb, pinfo, offset, tree); offset = dissect_edonkey_end_offset(tvb, pinfo, offset, tree); offset = dissect_edonkey_end_offset(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_SENDING_PART: /* Sending Part: DATA */ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); offset = dissect_edonkey_start_offset(tvb, pinfo, offset, tree); offset = dissect_edonkey_end_offset(tvb, pinfo, offset, tree); if (msg_end > offset) { bytes_remaining = msg_end - offset; proto_tree_add_text(tree, tvb, offset, bytes_remaining, "Message Data (%d bytes)", bytes_remaining); } break; case EDONKEY_MSG_SEARCH_USER_RESULTS: /* Search User Results: */ offset = dissect_edonkey_client_info_list(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_GET_SHARED_FILES: /* Get Shared Files: */ offset = dissect_edonkey_directory(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_SHARED_DIRS: /* Shared Dirs: */ offset = dissect_edonkey_directory_list(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_SHARED_FILES: /* Shared Files: */ offset = dissect_edonkey_directory(tvb, pinfo, offset, tree); offset = dissect_edonkey_file_info_list(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_HASHSET_ANSWER: /* Hashset Answer: */ offset = dissect_edonkey_hash_list(tvb, pinfo, offset, tree); break; default: proto_tree_add_text(tree, tvb, offset, length, "Message Data (%d bytes)", length); break; } return; } static void dissect_emule_tcp_message(guint8 msg_type, tvbuff_t *tvb, packet_info *pinfo _U_, int offset, int length, proto_tree *tree) { int msg_start, msg_end, bytes_remaining; guint32 packed_length; guint16 version, rank; if (tree == NULL) return; bytes_remaining = tvb_reported_length_remaining(tvb, offset); if ((length < 0) || (length > bytes_remaining)) length = bytes_remaining; if (length <= 0) return; msg_start = offset; msg_end = offset + length; switch (msg_type) { case EMULE_MSG_HELLO: /* eMule Hello: */ case EMULE_MSG_HELLO_ANSWER: /* eMule Hello Answer: */ version = tvb_get_letohs(tvb, offset); proto_tree_add_text(tree, tvb, offset, 2, "Version: %u", version); offset = dissect_edonkey_metatag_list(tvb, pinfo, offset+2, tree); break; case EMULE_MSG_QUEUE_RANKING: /* eMule Queue Ranking: */ rank = tvb_get_letohs(tvb, offset); proto_tree_add_text(tree, tvb, offset, 2, "Queue Ranking: %u", rank); break; case EMULE_MSG_SOURCES_REQUEST: /* Sources Request: */ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); break; case EMULE_MSG_SOURCES_ANSWER: /* Sources Answer:
*/ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); offset = dissect_emule_address_list(tvb, pinfo, offset, tree); break; case EMULE_MSG_DATA_COMPRESSED: /* Data Compressed: */ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); offset = dissect_edonkey_start_offset(tvb, pinfo, offset, tree); packed_length = tvb_get_letohl(tvb, offset); proto_tree_add_text(tree, tvb, offset, packed_length, "Packed Length: %u", packed_length); offset += 4; if (msg_end > offset) { bytes_remaining = msg_end - offset; proto_tree_add_text(tree, tvb, offset, bytes_remaining, "Compressed Message Data (%d bytes)", bytes_remaining); } break; default: dissect_edonkey_tcp_message(msg_type, tvb, pinfo, offset, length, tree); break; } return; } static void dissect_edonkey_udp_message(guint8 msg_type, tvbuff_t *tvb, packet_info *pinfo _U_, int offset, int length, proto_tree *tree) { int msg_start, msg_end, bytes_remaining; guint8 type; guint16 min, max; guint32 nusers, nfiles; if (tree == NULL) return; bytes_remaining = tvb_reported_length_remaining(tvb, offset); if ((length < 0) || (length > bytes_remaining)) length = bytes_remaining; if (length <= 0) return; msg_start = offset; msg_end = offset + length; switch (msg_type) { /* EDonkey UDP Messages */ case EDONKEY_MSG_UDP_CALLBACK_REQUEST: /* Callback Request:
*/ offset = dissect_edonkey_address(tvb, pinfo, offset, tree); offset = dissect_edonkey_client_id(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_UDP_CALLBACK_FAIL: /* Callback Fail: */ offset = dissect_edonkey_client_id(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_UDP_SERVER_INFO: /* Server Info: */ offset = dissect_edonkey_string(tvb, pinfo, offset, tree); offset = dissect_edonkey_string(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_UDP_SERVER_LIST: /* Server List:
*/ offset = dissect_edonkey_address_list(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_UDP_SEARCH_FILE_RESULTS: /* Search File Result: */ offset = dissect_edonkey_file_info(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_UDP_SEARCH_FILE: /* Search File: */ offset = dissect_edonkey_search_query(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_UDP_GET_SOURCES: /* Get Sources: */ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_UDP_FOUND_SOURCES: /* Found Sources:
*/ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); offset = dissect_edonkey_address_list(tvb, pinfo, offset, tree); break; case EDONKEY_MSG_UDP_SERVER_STATUS: /* Server Status: */ offset += 4; nusers = tvb_get_letohl(tvb, offset); nfiles = tvb_get_letohl(tvb, offset+4); proto_tree_add_text(tree, tvb, offset, 4, "Number of Users: %u", nusers); proto_tree_add_text(tree, tvb, offset+4, 4, "Number of Files: %u", nfiles); offset += 8; if (offset < msg_end) { nusers = tvb_get_letohl(tvb, offset); proto_tree_add_text(tree, tvb, offset, 4, "Max number of Users: %u", nusers); offset += 4; } break; /* Overnet UDP Messages */ case OVERNET_MSG_UDP_CONNECT: /* Connect: */ case OVERNET_MSG_UDP_PUBLICIZE: /* Publicize: */ offset = dissect_overnet_peer(tvb, pinfo, offset, tree); break; case OVERNET_MSG_UDP_CONNECT_REPLY: /* Connect Reply: */ offset = dissect_edonkey_list(tvb, pinfo, offset, tree, 2, "Overnet Peer", dissect_overnet_peer); break; case OVERNET_MSG_UDP_SEARCH: /* Search: */ type = tvb_get_guint8(tvb, offset); proto_tree_add_text(tree, tvb, offset, 1, "Search Type: %u", type); offset = dissect_edonkey_hash(tvb, pinfo, offset+1, tree); break; case OVERNET_MSG_UDP_SEARCH_INFO: /* Search Info: */ offset = dissect_edonkey_hash(tvb, pinfo, offset, tree); type = tvb_get_guint8(tvb, offset); min = tvb_get_letohs(tvb, offset+1); max = tvb_get_letohs(tvb, offset+3); proto_tree_add_text(tree, tvb, offset, 1, "Search Type: %u", type); proto_tree_add_text(tree, tvb, offset+1, 4, "Search Range: Min=%u Max=%u", min, max); break; case OVERNET_MSG_UDP_SEARCH_NEXT: /* Search Next: */ offset = dissect_edonkey_hash(tvb, pinfo, offset, tree); offset = dissect_edonkey_list(tvb, pinfo, offset, tree, 1, "Overnet Peer", dissect_overnet_peer); break; case OVERNET_MSG_UDP_SEARCH_RESULT: /* Search Result: */ case OVERNET_MSG_UDP_PUBLISH: /* Publish: */ offset = dissect_edonkey_hash(tvb, pinfo, offset, tree); offset = dissect_edonkey_hash(tvb, pinfo, offset, tree); offset = dissect_edonkey_metatag_list(tvb, pinfo, offset, tree); break; case OVERNET_MSG_UDP_SEARCH_END: /* Search End: */ offset = dissect_edonkey_hash(tvb, pinfo, offset, tree); break; case OVERNET_MSG_UDP_PUBLISH_ACK: /* Publish ACK: */ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); break; case OVERNET_MSG_UDP_IP_QUERY: /* IP Query: */ proto_tree_add_item(tree, hf_edonkey_port, tvb, offset, 2, TRUE); break; case OVERNET_MSG_UDP_IP_QUERY_ANSWER: /* IP Query Answer: */ offset = dissect_edonkey_client_id(tvb, pinfo, offset, tree); break; case OVERNET_MSG_UDP_IDENTIFY_REPLY: /* Identify Reply: */ /* ::=
*/ offset = dissect_edonkey_hash(tvb, pinfo, offset, tree); offset = dissect_edonkey_address(tvb, pinfo, offset, tree); break; case OVERNET_MSG_UDP_IDENTIFY_ACK: /* Identify Reply: */ proto_tree_add_item(tree, hf_edonkey_port, tvb, offset, 2, TRUE); break; case OVERNET_MSG_UDP_FIREWALL_CONNECTION: /* Firewall Connnection Ack: */ offset = dissect_edonkey_client_hash(tvb, pinfo, offset, tree); proto_tree_add_item(tree, hf_edonkey_port, tvb, offset, 2, TRUE); break; case OVERNET_MSG_UDP_FIREWALL_CONNECTION_ACK: /* Firewall Connnection Ack: */ case OVERNET_MSG_UDP_FIREWALL_CONNECTION_NACK: /* Firewall Connnection NAck: */ offset = dissect_edonkey_client_hash(tvb, pinfo, offset, tree); break; default: proto_tree_add_text(tree, tvb, offset, length, "Message Data (%d bytes)", length); break; } return; } static void dissect_emule_udp_message(guint8 msg_type, tvbuff_t *tvb, packet_info *pinfo _U_, int offset, int length, proto_tree *tree) { int msg_start, msg_end, bytes_remaining; guint16 rank; bytes_remaining = tvb_reported_length_remaining(tvb, offset); if ((length < 0) || (length > bytes_remaining)) length = bytes_remaining; if (length <= 0) return; msg_start = offset; msg_end = offset + length; switch (msg_type) { case EMULE_MSG_UDP_REASKFILEPING: /* Reask File Ping: */ offset = dissect_edonkey_file_hash(tvb, pinfo, offset, tree); break; case EMULE_MSG_UDP_REASKACK: /* Reask ACK: */ rank = tvb_get_letohs(tvb, offset); proto_tree_add_text(tree, tvb, offset, 2, "Queue Ranking: %u", rank); break; default: dissect_edonkey_udp_message(msg_type, tvb, pinfo, offset, length,tree); break; } return; } static void dissect_edonkey_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *edonkey_tree = NULL, *edonkey_msg_tree = NULL; int offset, bytes, messages; guint8 protocol, msg_type; guint32 msg_len; gchar *protocol_name, *message_name; void (*dissector)(guint8, tvbuff_t*, packet_info*, int, int, proto_tree*); if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, "eDonkey"); if (check_col(pinfo->cinfo, COL_INFO)) col_clear(pinfo->cinfo, COL_INFO); if (tree) { ti = proto_tree_add_item(tree, proto_edonkey, tvb, 0, -1, FALSE); edonkey_tree = proto_item_add_subtree(ti, ett_edonkey); } offset = 0; messages = 0; while (tvb_length_remaining(tvb, offset) >= EDONKEY_TCP_HEADER_LENGTH) { protocol = tvb_get_guint8(tvb, offset); msg_len = tvb_get_letohl(tvb, offset+1); protocol_name = match_strval(protocol, edonkey_protocols); if (protocol_name == NULL) { /* Not a recognized eDonkey protocol - probably a continuation */ if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, "eDonkey Continuation"); if (edonkey_tree) { bytes = tvb_length_remaining(tvb, offset); proto_tree_add_text(edonkey_tree, tvb, 0, -1, "Continuation data (%d bytes)", bytes); } return; } /* Add edonkey message tree */ if (edonkey_tree) { ti = proto_tree_add_item(edonkey_tree, hf_edonkey_message, tvb, offset, EDONKEY_TCP_HEADER_LENGTH + msg_len, FALSE); edonkey_msg_tree = proto_item_add_subtree(ti, ett_edonkey_message); proto_tree_add_uint_format(edonkey_msg_tree, hf_edonkey_protocol, tvb, offset, 1, protocol, "Protocol: %s (0x%02x)", protocol_name, protocol); proto_tree_add_uint(edonkey_msg_tree, hf_edonkey_message_length, tvb, offset+1, 4, msg_len); } /* Skip past the EDONKEY Header */ offset += EDONKEY_TCP_HEADER_LENGTH; if(tvb_reported_length_remaining(tvb, offset) <= 0) { /* There is not enough space for the msg_type - mark as fragment */ if (check_col(pinfo->cinfo, COL_INFO)) { if (messages == 0) col_append_fstr(pinfo->cinfo, COL_INFO, "%s TCP Message Fragment", protocol_name); else col_append_fstr(pinfo->cinfo, COL_INFO, "; %s TCP Message Fragment", protocol_name); } return; } if (check_col(pinfo->cinfo, COL_INFO)) { if (messages == 0) col_append_fstr(pinfo->cinfo, COL_INFO, "%s TCP", protocol_name); else col_append_fstr(pinfo->cinfo, COL_INFO, "; %s TCP", protocol_name); } msg_type = tvb_get_guint8(tvb, offset); switch (protocol) { case EDONKEY_PROTO_EDONKEY: message_name = val_to_str(msg_type, edonkey_tcp_msgs, "Unknown"); dissector = dissect_edonkey_tcp_message; break; case EDONKEY_PROTO_EMULE_EXT: message_name = val_to_str(msg_type, emule_tcp_msgs, val_to_str(msg_type, edonkey_tcp_msgs, "Unknown")); dissector = dissect_emule_tcp_message; break; default: message_name = "Unknown"; dissector = NULL; break; } if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", message_name); } if (edonkey_msg_tree) { proto_tree_add_uint_format(edonkey_msg_tree, hf_edonkey_message_type, tvb, offset, 1, msg_type, "Message Type: %s (0x%02x)", message_name, msg_type); if (dissector && (msg_len > 1)) (*dissector)(msg_type, tvb, pinfo, offset+1, msg_len-1, edonkey_msg_tree); } offset += msg_len; messages++; } } static void dissect_edonkey_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *edonkey_tree = NULL, *edonkey_msg_tree = NULL; int offset; guint8 protocol, msg_type; gchar *protocol_name, *message_name; if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, "eDonkey"); if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, "eDonkey UDP Message"); if (tree) { ti = proto_tree_add_item(tree, proto_edonkey, tvb, 0, -1, FALSE); edonkey_tree = proto_item_add_subtree(ti, ett_edonkey); } offset = 0; /* eDonkey UDP message - Assume that there is one message per packet */ if (tvb_length_remaining(tvb, offset) >= EDONKEY_UDP_HEADER_LENGTH) { protocol = tvb_get_guint8(tvb, offset); msg_type = tvb_get_guint8(tvb, offset+1); protocol_name = val_to_str(protocol, edonkey_protocols, "Unknown"); message_name = val_to_str(msg_type, edonkey_udp_msgs, "Unknown"); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s UDP: %s", protocol_name, message_name); } if (edonkey_tree) { ti = proto_tree_add_item(edonkey_tree, hf_edonkey_message, tvb, offset, -1, FALSE); edonkey_msg_tree = proto_item_add_subtree(ti, ett_edonkey_message); proto_tree_add_uint_format(edonkey_msg_tree, hf_edonkey_protocol, tvb, offset, 1, protocol, "Protocol: %s (0x%02x)", protocol_name, protocol); proto_tree_add_uint_format(edonkey_msg_tree, hf_edonkey_message_type, tvb, offset+1, 1, msg_type, "Message Type: %s (0x%02x)", message_name, msg_type); offset += EDONKEY_UDP_HEADER_LENGTH; switch (protocol) { case EDONKEY_PROTO_EDONKEY: dissect_edonkey_udp_message(msg_type, tvb, pinfo, offset, -1, edonkey_msg_tree); break; case EDONKEY_PROTO_EMULE_EXT: dissect_emule_udp_message(msg_type, tvb, pinfo, offset, -1, edonkey_msg_tree); break; default: break; } } } } void proto_register_edonkey(void) { static hf_register_info hf[] = { { &hf_edonkey_message, { "eDonkey Message", "edonkey.message", FT_NONE, BASE_NONE, NULL, 0, "eDonkey Message", HFILL } }, { &hf_edonkey_protocol, { "Protocol", "edonkey.protocol", FT_UINT8, BASE_HEX, NULL, 0, "eDonkey Protocol", HFILL } }, { &hf_edonkey_message_length, { "Message Length", "edonkey.message.length", FT_UINT32, BASE_DEC, NULL, 0, "eDonkey Message Length", HFILL } }, { &hf_edonkey_message_type, { "Message Type", "edonkey.message.type", FT_UINT8, BASE_HEX, NULL, 0, "eDonkey Message Type", HFILL } }, { &hf_edonkey_client_hash, { "Client Hash", "edonkey.client_hash", FT_BYTES, BASE_HEX, NULL, 0, "eDonkey Client Hash", HFILL } }, { &hf_edonkey_server_hash, { "Server Hash", "edonkey.server_hash", FT_BYTES, BASE_HEX, NULL, 0, "eDonkey Server Hash", HFILL } }, { &hf_edonkey_file_hash, { "File Hash", "edonkey.file_hash", FT_BYTES, BASE_HEX, NULL, 0, "eDonkey File Hash", HFILL } }, { &hf_edonkey_client_id, { "Client ID", "edonkey.clientid", FT_IPv4, BASE_DEC, NULL, 0, "eDonkey Client ID", HFILL } }, { &hf_edonkey_ip, { "IP", "edonkey.ip", FT_IPv4, BASE_DEC, NULL, 0, "eDonkey IP", HFILL } }, { &hf_edonkey_port, { "Port", "edonkey.port", FT_UINT16, BASE_DEC, NULL, 0, "eDonkey Port", HFILL } }, { &hf_edonkey_metatag, { "eDonkey Meta Tag", "edonkey.metatag", FT_NONE, BASE_NONE, NULL, 0, "eDonkey Meta Tag", HFILL } }, { &hf_edonkey_metatag_type, { "Meta Tag Type", "edonkey.metatag.type", FT_UINT8, BASE_HEX, NULL, 0, "eDonkey Meta Tag Type", HFILL } }, { &hf_edonkey_metatag_id, { "Meta Tag ID", "edonkey.metatag.id", FT_UINT8, BASE_HEX, NULL, 0, "eDonkey Meta Tag ID", HFILL } }, { &hf_edonkey_metatag_name, { "Meta Tag Name", "edonkey.metatag.name", FT_STRING, BASE_NONE, NULL, 0, "eDonkey Meta Tag Name", HFILL } }, { &hf_edonkey_metatag_namesize, { "Meta Tag Name Size", "edonkey.metatag.namesize", FT_UINT16, BASE_DEC, NULL, 0, "eDonkey Meta Tag Name Size", HFILL } }, { &hf_edonkey_search, { "eDonkey Search", "edonkey.search", FT_NONE, BASE_NONE, NULL, 0, "eDonkey Search", HFILL } }, { &hf_edonkey_hash, { "Hash", "edonkey.hash", FT_BYTES, BASE_HEX, NULL, 0, "eDonkey Hash", HFILL } }, { &hf_edonkey_string, { "String", "edonkey.string", FT_STRING, BASE_NONE, NULL, 0, "eDonkey String", HFILL } }, { &hf_edonkey_string_length, { "String Length", "edonkey.string_length", FT_UINT16, BASE_DEC, NULL, 0, "eDonkey String Length", HFILL } }, { &hf_edonkey_directory, { "Directory", "edonkey.directory", FT_STRING, BASE_NONE, NULL, 0, "eDonkey Directory", HFILL } }, { &hf_edonkey_fileinfo, { "eDonkey File Info", "edonkey.fileinfo", FT_NONE, BASE_NONE, NULL, 0, "eDonkey File Info", HFILL } }, { &hf_edonkey_serverinfo, { "eDonkey Server Info", "edonkey.serverinfo", FT_NONE, BASE_NONE, NULL, 0, "eDonkey Server Info", HFILL } }, { &hf_edonkey_clientinfo, { "eDonkey Client Info", "edonkey.clientinfo", FT_NONE, BASE_NONE, NULL, 0, "eDonkey Client Info", HFILL } }, { &hf_overnet_peer, { "Overnet Peer", "overnet.peer", FT_NONE, BASE_NONE, NULL, 0, "Overnet Peer", HFILL } }, }; static gint *ett[] = { &ett_edonkey, &ett_edonkey_message, &ett_edonkey_metatag, &ett_edonkey_search, &ett_edonkey_fileinfo, &ett_edonkey_serverinfo, &ett_edonkey_clientinfo, &ett_overnet_peer }; proto_edonkey = proto_register_protocol("eDonkey Protocol", "EDONKEY", "edonkey"); proto_register_field_array(proto_edonkey, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); register_dissector("edonkey.tcp", dissect_edonkey_tcp, proto_edonkey); register_dissector("edonkey.udp", dissect_edonkey_udp, proto_edonkey); } void proto_reg_handoff_edonkey(void) { dissector_handle_t edonkey_tcp_handle; dissector_handle_t edonkey_udp_handle; edonkey_tcp_handle = find_dissector("edonkey.tcp"); edonkey_udp_handle = find_dissector("edonkey.udp"); dissector_add("tcp.port", 4661, edonkey_tcp_handle); dissector_add("tcp.port", 4662, edonkey_tcp_handle); dissector_add("tcp.port", 4663, edonkey_tcp_handle); dissector_add("udp.port", 4665, edonkey_udp_handle); dissector_add("udp.port", 4672, edonkey_udp_handle); }