/* packet-freepastry.c * Routines for the FreePastry Binary protocol ion * Copyright 2007, David Dugoujon * * * Wireshark - 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 #include "packet-freepastry.h" /* desegmentation of FreePastry over TCP */ static gboolean freepastry_desegment = TRUE; static int proto_freepastry = -1; static int hf_freepastry_header_magic_number = -1; static int hf_freepastry_header_version_number = -1; static int hf_freepastry_header_source_route = -1; static int hf_freepastry_header_current_hop = -1; static int hf_freepastry_header_num_hop = -1; static int hf_freepastry_header_source_route_len = -1; static int hf_freepastry_header_header_direct = -1; static int hf_freepastry_header_app_id = -1; static int hf_freepastry_msg_header_address = -1; static int hf_freepastry_msg_header_has_sender = -1; static int hf_freepastry_msg_header_priority = -1; static int hf_freepastry_liveness_msg_type = -1; static int hf_freepastry_eisa_num_add = -1; static int hf_freepastry_eisa_ip = -1; static int hf_freepastry_eisa_port = -1; static int hf_freepastry_eisa_epoch = -1; static int hf_freepastry_id_type = -1; static int hf_freepastry_id_value = -1; static int hf_freepastry_versionkey_version = -1; static int hf_freepastry_fragmentkey_id = -1; static int hf_freepastry_ringid = -1; static int hf_freepastry_gcid_expiration = -1; static int hf_freepastry_rs_capacity = -1; static int hf_freepastry_rs_size = -1; static int hf_freepastry_rs_closest = -1; static int hf_freepastry_ns_size = -1; static int hf_freepastry_mns_type = -1; static int hf_freepastry_liveness_msg_sent_time = -1; static int hf_freepastry_ls_size = -1; static int hf_freepastry_ls_num_unique_handle = -1; static int hf_freepastry_ls_cw_size = -1; static int hf_freepastry_ls_ccw_size = -1; static int hf_freepastry_ls_handle_index = -1; static int hf_freepastry_router_msg_type = -1; static int hf_freepastry_join_msg_type = -1; static int hf_freepastry_leafset_msg_type = -1; static int hf_freepastry_routingtable_msg_type = -1; static int hf_freepastry_msg_size = -1; static int hf_freepastry_commonapi_msg_type = -1; static int hf_freepastry_direct_msg_type = -1; static int hf_freepastry_direct_msg_version = -1; static int hf_freepastry_router_msg_version = -1; static int hf_freepastry_commonapi_msg_version = -1; static int hf_freepastry_join_msg_version = -1; static int hf_freepastry_routingtable_msg_version = -1; static int hf_freepastry_leafset_proto_msg_version = -1; static int hf_freepastry_direct = -1; static int hf_freepastry_router = -1; static int hf_freepastry_commonapi = -1; static int hf_freepastry_join = -1; static int hf_freepastry_routingtable = -1; static int hf_freepastry_leafset_proto = -1; static int hf_freepastry_liveness = -1; static gint ett_freepastry = -1; static gint ett_freepastry_eisa = -1; static gint ett_freepastry_isa = -1; static gint ett_freepastry_nh = -1; static gint ett_freepastry_ns = -1; static gint ett_freepastry_rs = -1; static gint ett_freepastry_ls = -1; static gint ett_freepastry_ls_cw = -1; static gint ett_freepastry_ls_ccw = -1; static dissector_handle_t freepastry_udp_handle; static dissector_handle_t freepastry_tcp_handle; static dissector_table_t subdissector_message_version_table; /* * State information stored with a conversation. */ struct freepastry_tcp_stream_data { guint32 id; /*A unique ID (the frame number)that identify the header*/ gboolean is_app_stream; /* Is it a normal FreePastry Socket? */ }; /* Address mapping */ static const value_string freepastry_address[] = { { DIRECT_ACCESS, "Direct Access" }, { ROUTER, "Router" }, { JOIN_PROTOCOL, "Join Protocol" }, { LEAFSET_PROTOCOL, "Leafset Protocol" }, { ROUTINGTABLE_PROTOCOL, "Route Protocol" }, { 0, NULL } }; /*Messages for "Direct access" module*/ static const value_string freepastry_direct_access_msg[] = { { SOURCEROUTE_MSG, "Source Route" }, { LEAFSET_REQUEST_MSG, "LeafSet Request" }, { LEAFSET_RESPONSE_MSG, "LeafSet Response" }, { NODE_ID_REQUEST_MSG, "Node ID Request" }, { NODE_ID_RESPONSE_MSG, "Node ID Response" }, { ROUTE_ROW_REQUEST_MSG, "Route Row Request" }, { ROUTE_ROW_RESPONSE_MSG, "Route Row Response" }, { SOURCEROUTE_REQUEST_MSG, "Routes Request" }, { SOURCEROUTE_RESPONSE_MSG,"Routes Response" }, { 0, NULL } }; /*Messages for "Join" module*/ static const value_string freepastry_join_msg[] = { { JOIN_REQUEST, "Join Request" }, { CONSISTENT_JOIN_MSG, "Consistent Join" }, { 0, NULL } }; /*Messages for "Router" module*/ static const value_string freepastry_router_msg[] = { { ROUTE, "Route Message" }, { 0, NULL } }; /*Messages for "Leafset Maintenance" module*/ static const value_string freepastry_leafset_msg[] = { { REQUEST_LEAFSET, "Request LeafSet" }, { BROADCAST_LEAFSET, "Broadcast LeafSet" }, { 0, NULL } }; /*Messages for "Routing Table Maintenance" module*/ static const value_string freepastry_routingtable_msg[] = { { REQUEST_ROUTE_ROW, "Request Route Row" }, { BROADCAST_ROUTE_ROW, "Broadcast Route Row" }, { 0, NULL } }; /*Messages for "Common API" module*/ static const value_string freepastry_commonapi_msg[] = { { 2, "Pastry Endpoint" }, { 0, NULL } }; /* Message Priority */ static const value_string freepastry_priority[] = { { -15, "Max" }, { -10, "High" }, { -5, "Medium High" }, { 0, "Medium" }, { 5, "Medium Low" }, { 10, "Low" }, { 0, NULL } }; /* ID type */ static const value_string freepastry_id_type[] = { { ID_TYPE_NORMAL, "Normal" }, { ID_TYPE_RINGID, "RingId" }, { ID_TYPE_GCID, "GCId" }, { ID_TYPE_VERSIONKEY, "Version Key" }, { ID_TYPE_FRAGMENTKEY, "Fragment Key" }, { 0, NULL } }; /*UDP Message type mapping*/ static const value_string freepastry_liveness_message[] = { { IP_ADDRESS_REQUEST_MSG, "IP Address Request" }, { IP_ADDRESS_RESPONSE_MSG, "IP Address Response" }, { PING_MSG, "Ping Request" }, { PING_RESPONSE_MESSAGE, "Ping Response" }, { WRONG_EPOCH_MESSAGE, "Wrong Epoch" }, { 0, NULL } }; /* * Start: Common FreePastry Objects dissection. * These functions can be used by other files in the FreePastry plugin * (Common API dissectors, core message dissectors). */ /** * @return the size of a "EpochInetSocketAddress" object. **/ gint get_epoch_inet_socket_address_len(tvbuff_t *tvb, gint offset) { guint8 nb_addr; nb_addr = tvb_get_guint8(tvb, offset); return (9+nb_addr*6); } /** * Decode a "EpochInetSocketAddress" object. * @return the new offset or -1 on error. **/ gint decode_epoch_inet_socket_address(tvbuff_t *tvb, proto_tree *parent_tree, gint offset, gchar *attribute_name) { proto_item *ti = NULL; proto_tree *epoch_inet_socket_address_tree = NULL; proto_tree *inet_socket_address_tree = NULL; guint8 nb_addr; gchar *ip_str; guint16 port_number; int i; /*Get the number of (IPv4 address, port number) couple*/ nb_addr = tvb_get_guint8(tvb, offset); offset++; if (tvb_reported_length_remaining(tvb, offset) < (8+nb_addr*6)){ proto_tree_add_text(parent_tree, tvb, offset, -1, "Too short EISA attribute!"); return -1; } /*For each InetSocketAddress*/ for (i = 0; i < nb_addr; ++i){ ip_str = ip_to_str(tvb_get_ptr(tvb, offset, 4)); port_number = tvb_get_ntohs(tvb, offset+4); if (i == 0) { ti = proto_tree_add_text(parent_tree, tvb, (offset -1), (nb_addr*6+ 9), "%s: %s:%d (EpochInetSocketAddress with %d address(es))", attribute_name, ip_str, port_number, nb_addr); epoch_inet_socket_address_tree = proto_item_add_subtree(ti, ett_freepastry_eisa); proto_tree_add_item(epoch_inet_socket_address_tree, hf_freepastry_eisa_num_add, tvb, (offset-1), 1, FALSE); } ti = proto_tree_add_text(epoch_inet_socket_address_tree, tvb, offset, 6, "InetSocketAddress #%d %s:%d", i+1, ip_str, port_number); inet_socket_address_tree = proto_item_add_subtree(ti, ett_freepastry_isa); proto_tree_add_ipv4(inet_socket_address_tree, hf_freepastry_eisa_ip, tvb, offset, 4, tvb_get_ipv4(tvb, offset)); proto_tree_add_uint(inet_socket_address_tree, hf_freepastry_eisa_port, tvb, offset+4, 2, port_number); offset += 6; } if (nb_addr != 0) { /*Get the epoch (random number)*/ proto_tree_add_item(epoch_inet_socket_address_tree, hf_freepastry_eisa_epoch, tvb, offset, 8, FALSE); offset += 8; } return offset; } /** * @return the size of a "Node Handle" object. **/ gint get_node_handle_len(tvbuff_t *tvb, gint offset) { guint8 nb_addr; nb_addr = tvb_get_guint8(tvb, offset); return (29+nb_addr*6); } /** * Build a buffer with a full representation of the ID. * @return a buffer containing the ID. **/ gchar* get_id_full(tvbuff_t *tvb, gint offset) { guint32 id1, id2, id3, id4, id5; id1 = tvb_get_ntohl(tvb, offset + 16); id2 = tvb_get_ntohl(tvb, offset + 12); id3 = tvb_get_ntohl(tvb, offset + 8); id4 = tvb_get_ntohl(tvb, offset + 4); id5 = tvb_get_ntohl(tvb, offset); return ep_strdup_printf( "0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", (id1 >> 24) & 0xff, (id1 >> 16) & 0xff, (id1 >> 8) & 0xff, id1 & 0xff, (id2 >> 24) & 0xff, (id2 >> 16) & 0xff, (id2 >> 8) & 0xff, id2 & 0xff, (id3 >> 24) & 0xff, (id3 >> 16) & 0xff, (id3 >> 8) & 0xff, id3 & 0xff, (id4 >> 24) & 0xff, (id4 >> 16) & 0xff, (id4 >> 8) & 0xff, id4 & 0xff, (id5 >> 24) & 0xff, (id5 >> 16) & 0xff, (id5 >> 8) & 0xff, id5 & 0xff); } /** * Build a buffer with a truncated representation of the ID. * @return a buffer containing the truncted ID. **/ gchar* get_id(tvbuff_t *tvb, gint offset) { guint32 id = tvb_get_ntohl(tvb, offset + 16); /* returned buffer is automatically freed once the current packet dissection completes*/ return ep_strdup_printf(" <0x%02X%02X%02X..>", (id >> 24) & 0xff, (id >> 16) & 0xff, (id >> 8) & 0xff); } /** * Print an ID in the info column. * Used by common API applications. * @return the new offset or -1 on failure. **/ gint print_id_into_col_info(tvbuff_t *tvb, packet_info *pinfo, gint offset, gchar* info_string){ gint16 type; /*We need to read the ID type*/ if (tvb_reported_length_remaining(tvb, offset) < 2){ col_append_fstr(pinfo->cinfo, COL_INFO, " %s (Malformed Message)", info_string); return -1; } type = tvb_get_ntohs(tvb, offset); offset +=2; switch (type){ case ID_TYPE_NORMAL: return print_id_value_into_col_info(tvb,pinfo, offset, info_string); case ID_TYPE_RINGID: return print_ringid_into_col_info(tvb,pinfo, offset, info_string); case ID_TYPE_GCID: return print_gcid_into_col_info(tvb,pinfo, offset, info_string); case ID_TYPE_VERSIONKEY: case ID_TYPE_FRAGMENTKEY: default: return -1; } } /** * Print an ID value (2O bytes) in the info column. * @return the new offset or -1 on failure. **/ gint print_id_value_into_col_info(tvbuff_t *tvb, packet_info *pinfo, gint offset, gchar* info_string){ if (tvb_reported_length_remaining(tvb, offset) < 20){ col_append_fstr(pinfo->cinfo, COL_INFO, " %s (Malformed Message)", info_string); return -1; } col_append_fstr(pinfo->cinfo, COL_INFO, " %s%s", info_string, get_id(tvb, offset)); return offset + 20; } /** * Print a ring ID in the info column. * @return the new offset or -1 on failure. **/ gint print_ringid_into_col_info(tvbuff_t *tvb, packet_info *pinfo, gint offset, gchar* info_string){ if (tvb_reported_length_remaining(tvb, offset) < 44){ col_append_fstr(pinfo->cinfo, COL_INFO, " %s (Malformed Message)", info_string); return -1; } else { gint16 type = tvb_get_ntohs(tvb, offset); if (type == ID_TYPE_NORMAL) { type = tvb_get_ntohs(tvb, offset + 22); if (type == ID_TYPE_NORMAL){ col_append_fstr(pinfo->cinfo, COL_INFO, " %s%s%s", info_string, get_id(tvb, offset + 2), get_id(tvb, offset + 24)); } else { col_append_fstr(pinfo->cinfo, COL_INFO, info_string); } } else { col_append_fstr(pinfo->cinfo, COL_INFO, info_string); } return offset +44; } } /** * Print a GCID in the info column. * @return the new offset or -1 on failure. **/ gint print_gcid_into_col_info(tvbuff_t *tvb, packet_info *pinfo, gint offset, gchar* info_string){ if (tvb_reported_length_remaining(tvb, offset) < 30){ col_append_fstr(pinfo->cinfo, COL_INFO, " %s (Malformed Message)", info_string); return -1; } else { gint16 type = tvb_get_ntohs(tvb, offset); if (type == ID_TYPE_GCID) { type = tvb_get_ntohs(tvb, offset + 10); if (type == ID_TYPE_NORMAL){ col_append_fstr(pinfo->cinfo, COL_INFO, " %s%s", info_string, get_id(tvb, offset + 12)); } else { /*Do not try to print complex ID here*/ col_append_fstr(pinfo->cinfo, COL_INFO, info_string); } } else { col_append_fstr(pinfo->cinfo, COL_INFO, " %s (Malformed Message)", info_string); return -1; } return offset +44; } } /** * Decode into the tree an ID. * Used by common API applications. * @return the new offset or -1 on failure. **/ gint decode_type_and_id(tvbuff_t *tvb, proto_tree *tree, gint offset) { gint16 type; if (tvb_reported_length_remaining(tvb, offset) < 2){ proto_tree_add_text(tree, tvb, offset, -1 , "Too short attributes!"); return -1; } type = tvb_get_ntohs(tvb, offset); proto_tree_add_item(tree, hf_freepastry_id_type, tvb, offset, 2, FALSE); return decode_id_from_type(tvb, tree, type, offset + 2); } /** * Decode into the tree an ID depending on its type. * @return the new offset or -1 on failure. **/ gint decode_id_from_type(tvbuff_t *tvb, proto_tree *tree, short type, gint offset) { switch (type){ case ID_TYPE_NORMAL: return decode_id_value(tvb,tree, offset); case ID_TYPE_RINGID: return decode_ringid(tvb,tree, offset); case ID_TYPE_GCID: return decode_gcid(tvb, tree, offset); case ID_TYPE_VERSIONKEY: return decode_versionkey(tvb, tree, offset); case ID_TYPE_FRAGMENTKEY: return decode_fragmentkey(tvb, tree, offset); default: return -1; } } /** * Decode into the tree an ID value. * @return the new offset or -1 on failure. **/ gint decode_id_value(tvbuff_t *tvb, proto_tree *tree, gint offset) { if (tvb_reported_length_remaining(tvb, offset) < 20){ proto_tree_add_text(tree, tvb, offset, -1, "Too short attributes!"); return -1; } proto_tree_add_string(tree, hf_freepastry_id_value, tvb, offset, 20, get_id_full(tvb, offset)); return offset + 20; } /** * Decode into the tree a ring ID. * @return the new offset or -1 on failure. **/ gint decode_ringid(tvbuff_t *tvb, proto_tree *tree, gint offset) { /*Ring Id*/ offset = decode_type_and_id(tvb, tree, offset); if (offset != -1){ /* Id*/ offset = decode_type_and_id(tvb, tree, offset); } return offset; } /** * Decode into the tree a GCID. * @return the new offset or -1 on failure. **/ gint decode_gcid(tvbuff_t *tvb, proto_tree *tree, gint offset) { gint16 type; if (tvb_reported_length_remaining(tvb, offset) < 2){ proto_tree_add_text(tree, tvb, offset, -1 , "Too short attributes!"); return -1; } type = tvb_get_ntohs(tvb, offset); proto_tree_add_item(tree, hf_freepastry_id_type, tvb, offset, 2, type); if (type != ID_TYPE_GCID){ proto_tree_add_text(tree, tvb, offset, -1 , "Not a GCID!"); return -1; } offset += 2; if (tvb_reported_length_remaining(tvb, offset) < 8){ proto_tree_add_text(tree, tvb, offset, -1 , "Too short attributes!"); return -1; } proto_tree_add_item(tree, hf_freepastry_gcid_expiration, tvb, offset, 8, FALSE); return decode_type_and_id(tvb, tree, offset + 8); } /** * Decode into the tree a VersionKey (used by Glacier). * @return the new offset or -1 on failure. **/ gint decode_versionkey(tvbuff_t *tvb, proto_tree *tree, gint offset) { if (tvb_reported_length_remaining(tvb, offset) < 8){ proto_tree_add_text(tree, tvb, offset, -1 , "Too short attributes!"); return -1; } proto_tree_add_item(tree, hf_freepastry_versionkey_version, tvb, offset, 8, FALSE); return decode_type_and_id(tvb, tree, offset + 8); } /** * Decode into the tree a FragmentKey (used by Glacier). * @return the new offset or -1 on failure. **/ gint decode_fragmentkey(tvbuff_t *tvb, proto_tree *tree, gint offset) { if (tvb_reported_length_remaining(tvb, offset) < 4){ proto_tree_add_text(tree, tvb, offset, -1 , "Too short attributes!"); return -1; } proto_tree_add_item(tree, hf_freepastry_fragmentkey_id, tvb, offset, 4, FALSE); return decode_versionkey(tvb, tree, offset + 4); } /** * Build a buffer with a truncated representation of the ID in a Node Handle. * @return a buffer containing the truncted ID. **/ gchar* get_id_from_node_handle(tvbuff_t *tvb, gint offset) { guint32 id; offset += get_epoch_inet_socket_address_len(tvb, offset); id = tvb_get_ntohl(tvb, offset + 16); /* returned buffer is automatically freed once the current packet dissection completes*/ return ep_strdup_printf("<0x%02X%02X%02X..>", (id >> 24) & 0xff, (id >> 16) & 0xff, (id >> 8) & 0xff); } /** * Decode a "Node Handle" object. * @return the new offset or -1 on error. **/ gint decode_nodehandle(tvbuff_t *tvb, proto_tree *parent_tree, gint offset, gchar *attribute_name) { proto_item *ti = NULL; proto_tree *node_handle_tree = NULL; ti = proto_tree_add_text(parent_tree, tvb, offset, 1, attribute_name); node_handle_tree = proto_item_add_subtree(ti, ett_freepastry_nh); offset = decode_epoch_inet_socket_address(tvb, node_handle_tree, offset, "EpochInetSocketAddress"); if (offset != -1){ /*20 bytes = ID Length*/ if (tvb_reported_length_remaining(tvb, offset) >= 20) { gchar* short_id = get_id(tvb, offset); proto_item_append_text(ti, short_id); proto_tree_add_string(node_handle_tree, hf_freepastry_id_value, tvb, offset, 20, get_id_full(tvb, offset)); offset += 20; proto_item_set_end(ti, tvb, offset); } else { proto_tree_add_text(node_handle_tree, tvb, offset, -1, "Too short attribute!"); return -1; } } return offset; } /** * Decode a "Route Set" object. * @return the new offset or -1 on error. **/ gint decode_routeset(tvbuff_t *tvb, proto_tree *parent_tree, gint offset, gchar *attribute_name) { proto_item *ti = NULL; proto_tree *routeset_tree = NULL; guint8 routeset_size; guint8 routeset_closest; int i; ti = proto_tree_add_text(parent_tree, tvb, offset, 1, "%s :", attribute_name); routeset_tree = proto_item_add_subtree(ti, ett_freepastry_rs); proto_tree_add_item(routeset_tree, hf_freepastry_rs_capacity, tvb, offset, 1, FALSE); offset++; routeset_size = tvb_get_guint8(tvb, offset); proto_tree_add_uint(routeset_tree, hf_freepastry_rs_size, tvb, offset, 1, routeset_size); offset++; routeset_closest = tvb_get_guint8(tvb, offset); proto_tree_add_uint(routeset_tree, hf_freepastry_rs_closest, tvb, offset, 1, routeset_closest); offset++; proto_item_append_text(ti, " (%d Node Handles)", routeset_size); for (i=0; i < routeset_size; ++i){ if ((i+1) == routeset_closest){ proto_item_append_text(ti, " (closest %s)", get_id_from_node_handle(tvb, offset)); } offset = decode_nodehandle(tvb, routeset_tree, offset, "Node Handle"); if (offset == -1) { return -1; } } proto_item_set_end(ti, tvb, offset); return offset; } /** * Decode a "Node Handle Set" object. * @return the new offset or -1 on error. **/ gint decode_nodehandleset(tvbuff_t *tvb, proto_tree *parent_tree, gint offset, gchar *attribute_name) { proto_item *ti = NULL; proto_tree *nodeset_tree = NULL; guint16 nodeset_size; int i; ti = proto_tree_add_text(parent_tree, tvb, offset, 1, "%s :", attribute_name); nodeset_tree = proto_item_add_subtree(ti, ett_freepastry_ns); nodeset_size = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(nodeset_tree, hf_freepastry_ns_size, tvb, offset, 2, nodeset_size); offset +=2; proto_item_append_text(ti, " (%d Node Handles)", nodeset_size); for (i=0; i < nodeset_size; ++i){ offset = decode_nodehandle(tvb, nodeset_tree, offset, "Node Handle"); if (offset == -1) { return -1; } } proto_item_set_end(ti, tvb, offset); return offset; } /** * Decode a "Multiring Node Handle Set" object. * @return the new offset or -1 on error. **/ gint decode_multiring_nodehandleset(tvbuff_t *tvb, proto_tree *parent_tree, gint offset, gchar *attribute_name) { offset = decode_type_and_id(tvb, parent_tree, offset); proto_tree_add_item(parent_tree, hf_freepastry_mns_type, tvb, offset + 20, 2, FALSE); offset = decode_nodehandleset(tvb, parent_tree, offset + 22, attribute_name); return offset; } /** * @return the size of a Leafset object. **/ gint get_leafset_len(tvbuff_t *tvb, gint offset) { guint8 num_unique_handle; guint8 num_cw_size; guint8 num_ccw_size; int i; guint8 pos = offset +1; num_unique_handle = tvb_get_guint8(tvb, pos); pos++; num_cw_size = tvb_get_guint8(tvb, pos); pos++; num_ccw_size = tvb_get_guint8(tvb, pos); pos++; pos += get_node_handle_len(tvb, pos); for (i = 0; i < num_unique_handle; ++i){ pos += get_node_handle_len(tvb, pos); } return (pos + num_cw_size + num_ccw_size - offset); } /** * Decode a "Leafset" object. * @return the new offset or -1 on error. **/ gint decode_leafset(tvbuff_t *tvb, proto_tree *parent_tree, gint offset, gchar *attribute_name) { proto_item *ti = NULL; proto_item *ti_cw = NULL; proto_item *ti_ccw = NULL; proto_tree *leafset_tree = NULL; proto_tree *cw_tree = NULL; proto_tree *ccw_tree = NULL; guint8 num_unique_handle; guint8 num_cw_size; guint8 num_ccw_size; /*these vars are for drawing the LeafSet, they need to be filled in with the sub values before the LS can be rendered*/ gchar *base_handle_id; gchar *node_handle_id[24]; guint8 ccw_index[12]; guint8 cw_index[12]; guint32 leafset_string_length; gchar *leafset_string; guint32 leafset_string_offset; int i; ti = proto_tree_add_text(parent_tree, tvb, offset, 1, attribute_name); leafset_tree = proto_item_add_subtree(ti, ett_freepastry_ls); /*The total capacity of the leafset (not including the base handle)*/ proto_tree_add_item(leafset_tree, hf_freepastry_ls_size, tvb, offset, 1, FALSE); offset++; /*The number of NodeHandles to read*/ num_unique_handle = tvb_get_guint8(tvb, offset); if (num_unique_handle > 24){ proto_tree_add_text(leafset_tree, tvb, 1, -1, "Too many node handles"); return -1; } proto_tree_add_uint(leafset_tree, hf_freepastry_ls_num_unique_handle, tvb, offset, 1, num_unique_handle); offset++; /*The number of element of the clockwise similar set*/ num_cw_size = tvb_get_guint8(tvb, offset); if (num_cw_size > 12){ proto_tree_add_text(leafset_tree, tvb, 1, -1, "Too many node handles in clockwise similar set"); return -1; } proto_tree_add_uint(leafset_tree, hf_freepastry_ls_cw_size, tvb, offset, 1, num_cw_size); offset++; /*The number of element of the counter clockwise similar set*/ num_ccw_size = tvb_get_guint8(tvb, offset); if (num_ccw_size > 12){ proto_tree_add_text(leafset_tree, tvb, 1, -1, "Too many node handles in counterclockwise similar set"); return -1; } proto_tree_add_uint(leafset_tree, hf_freepastry_ls_ccw_size, tvb, offset, 1, num_ccw_size); offset++; /*The base NodeHandle*/ base_handle_id = get_id_from_node_handle(tvb,offset); offset = decode_nodehandle(tvb, leafset_tree, offset, "Base Node Handle"); /*The unique handles*/ for (i = 0; i < num_unique_handle; ++i){ if (offset == -1) { return -1; } node_handle_id[i] = get_id_from_node_handle(tvb,offset); offset = decode_nodehandle(tvb, leafset_tree, offset, ep_strdup_printf("Node Handle #%d", i)); } /*The cw addresses*/ ti_cw = proto_tree_add_text(leafset_tree, tvb, offset, num_cw_size, "Clockwise Similar Set"); cw_tree = proto_item_add_subtree(ti_cw, ett_freepastry_ls_cw); for (i = 0; i < num_cw_size; ++i){ cw_index[i] = tvb_get_guint8(tvb, offset); proto_tree_add_item(cw_tree, hf_freepastry_ls_handle_index, tvb, offset, 1, FALSE); offset++; } proto_item_set_end(ti_cw, tvb, offset); /*The ccw addresses*/ ti_ccw = proto_tree_add_text(leafset_tree, tvb, offset, num_ccw_size, "Counter Clockwise Similar Set"); ccw_tree = proto_item_add_subtree(ti_ccw, ett_freepastry_ls_ccw); for (i = 0; i < num_ccw_size; ++i){ ccw_index[i] = tvb_get_guint8(tvb, offset); proto_tree_add_item(ccw_tree, hf_freepastry_ls_handle_index, tvb, offset, 1, FALSE); offset++; } proto_item_set_end(ti_ccw, tvb, offset); /* draw the leafset: heading space 2 brackets, null terminator */ leafset_string_length = 4+(num_ccw_size+num_cw_size+1)*ID_PRINT_SIZE; leafset_string = ep_alloc(leafset_string_length); leafset_string_offset = 0; g_snprintf(leafset_string, leafset_string_length - leafset_string_offset, " "); leafset_string_offset++; for (i=num_ccw_size-1; i>=0; i--) { g_snprintf(leafset_string+leafset_string_offset, leafset_string_length - leafset_string_offset, node_handle_id[ccw_index[i]]); leafset_string_offset+=ID_PRINT_SIZE; } g_snprintf(leafset_string+leafset_string_offset, leafset_string_length - leafset_string_offset, "[%s]", base_handle_id); leafset_string_offset+=2+ID_PRINT_SIZE; for (i=0; i < num_ccw_size; i++) { g_snprintf(leafset_string+leafset_string_offset, leafset_string_length - leafset_string_offset, node_handle_id[cw_index[i]]); leafset_string_offset+=ID_PRINT_SIZE; } proto_item_append_text(ti,leafset_string); proto_item_set_end(ti, tvb, offset); return offset; } gint decode_message_version(tvbuff_t *tvb, proto_tree *tree, gint offset, guint32 address) { /*We already know that there is enough byte for version field here*/ switch (address){ case DIRECT_ACCESS: proto_tree_add_item(tree, hf_freepastry_direct_msg_version, tvb, offset, 1, FALSE); break; case ROUTER: proto_tree_add_item(tree, hf_freepastry_router_msg_version, tvb, offset, 1, FALSE); break; case JOIN_PROTOCOL: proto_tree_add_item(tree, hf_freepastry_join_msg_version, tvb, offset, 1, FALSE); break; case LEAFSET_PROTOCOL: proto_tree_add_item(tree, hf_freepastry_leafset_proto_msg_version, tvb, offset, 1, FALSE); break; case ROUTINGTABLE_PROTOCOL: proto_tree_add_item(tree, hf_freepastry_routingtable_msg_version, tvb, offset, 1, FALSE); break; default:/*Common API*/ proto_tree_add_item(tree, hf_freepastry_commonapi_msg_version, tvb, offset, 1, FALSE); } return offset+1; } /* * End: Common FreePastry Objects dissection. */ /** * Dissect a FreePastry UDP Message **/ static void dissect_freepastry_common_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gint offset = 0; guint8 nb_hops = 0; guint32 address; guint16 type = 0; gboolean has_sender = FALSE; int i = 0; proto_item *ti = NULL; proto_tree *freepastry_tree = NULL; if (tvb_length(tvb) < 16 ) { return; } if (tvb_get_ntohl(tvb, offset) != PASTRY_MAGIC_NUMBER){ return; } /*This is a FreePastry message for sure*/ if (check_col(pinfo->cinfo, COL_PROTOCOL)){ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FreePastry"); } if (check_col(pinfo->cinfo, COL_INFO)){ col_clear (pinfo->cinfo, COL_INFO); col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d", pinfo->srcport, pinfo->destport); } if (tree){ ti = proto_tree_add_item(tree, proto_freepastry, tvb, 0, -1, FALSE); freepastry_tree = proto_item_add_subtree(ti, ett_freepastry); proto_tree_add_item_hidden(tree, hf_freepastry_liveness, tvb, offset, -1, FALSE); proto_tree_add_item(freepastry_tree, hf_freepastry_header_magic_number, tvb, offset, 4, FALSE); proto_tree_add_item(freepastry_tree, hf_freepastry_header_version_number, tvb, offset+4, 4, FALSE); proto_tree_add_item(freepastry_tree, hf_freepastry_header_current_hop, tvb, offset+8, 1, FALSE); } /*magic_number + version + hop_counter*/ offset += 9; nb_hops = tvb_get_guint8(tvb, offset); if (tree){ proto_tree_add_uint(freepastry_tree, hf_freepastry_header_num_hop, tvb, offset, 1, nb_hops); proto_tree_add_item(freepastry_tree, hf_freepastry_header_source_route_len, tvb, offset + 1, 2, FALSE); } /*num_hops + source_route_len*/ offset += 3; if (tree){ for (i = 0; i < nb_hops; ++i){ offset = decode_epoch_inet_socket_address(tvb, freepastry_tree, offset, "Hop"); if (offset == -1){ return; } } } else { for (i = 0; i < nb_hops; ++i){ offset += get_epoch_inet_socket_address_len(tvb, offset); } } address = tvb_get_ntohl(tvb, offset); /*app specific socket*/ if (address != 0){ if (check_col(pinfo->cinfo, COL_INFO)){ col_append_str(pinfo->cinfo, COL_INFO, "Application Specific Message"); } return; } /*has sender?*/ if (tvb_get_guint8(tvb, offset+4) != 0){ has_sender = TRUE; } if (tree){ proto_tree_add_item(freepastry_tree, hf_freepastry_msg_header_address, tvb, offset, 4, FALSE); proto_tree_add_boolean(freepastry_tree, hf_freepastry_msg_header_has_sender, tvb, offset+4, 1, has_sender); proto_tree_add_item(freepastry_tree, hf_freepastry_msg_header_priority, tvb, offset+5, 1, FALSE); } offset +=6; /*parse type*/ type = tvb_get_ntohs(tvb, offset); if (check_col(pinfo->cinfo, COL_INFO)){ col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(type, freepastry_liveness_message, "")); } if (tree){ proto_tree_add_item(freepastry_tree, hf_freepastry_liveness_msg_type, tvb, offset, 2, FALSE); offset += 2; /*parse nodehandle sender*/ if (has_sender){ offset = decode_nodehandle(tvb, freepastry_tree, offset, "Sender"); } if (offset != -1) { switch (type) { case IP_ADDRESS_REQUEST_MSG: case IP_ADDRESS_RESPONSE_MSG: case PING_MSG: case PING_RESPONSE_MESSAGE: proto_tree_add_item(freepastry_tree, hf_freepastry_liveness_msg_sent_time, tvb, offset, 8, FALSE); break; case WRONG_EPOCH_MESSAGE: proto_tree_add_item(freepastry_tree, hf_freepastry_liveness_msg_sent_time, tvb, offset, 8, FALSE); offset += 8; offset = decode_epoch_inet_socket_address(tvb, tree, offset, "Incorrect"); if (offset != -1){ offset = decode_epoch_inet_socket_address(tvb, tree, offset, "Correct"); } break; default: proto_tree_add_text(tree, tvb, offset, 1, "Unkown type"); } } } } /* * Start: TCP FreePastry Core Message dissection. */ /** * Decode the common structure of a FreePastry TCP message. * TCP fragments are already reassembled (message is complete) * Such a function is needed because a FreePastry Message can be * Encapsulated into another one (e.g. into a Route Message). * This function can be called from this file or a * packet-freepastry-core-vX.c file. **/ void decode_freepastry_tcp_msg_invariant(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset, guint32 address) { gboolean has_sender = FALSE; gint16 type = 0; sub_message_info_t *sub_message_info = NULL; tvbuff_t *next_tvb = NULL; const gchar *type_string; /*has sender?*/ if (tvb_get_guint8(tvb, offset) != 0){ has_sender = TRUE; } if (tree){ proto_tree_add_boolean(tree, hf_freepastry_msg_header_has_sender, tvb, offset, 1, has_sender); proto_tree_add_item(tree, hf_freepastry_msg_header_priority, tvb, offset+1, 1, FALSE); } offset += 2; /*parse type*/ type = tvb_get_ntohs(tvb, offset); switch (address){ case DIRECT_ACCESS: type_string = val_to_str(type, freepastry_direct_access_msg, ""); if (tree){ proto_tree_add_item_hidden(tree, hf_freepastry_direct, tvb, offset, -1, FALSE); proto_tree_add_item(tree, hf_freepastry_direct_msg_type, tvb, offset, 2, FALSE); } break; case ROUTER: type_string = val_to_str(type, freepastry_router_msg, ""); if (tree){ proto_tree_add_item_hidden(tree, hf_freepastry_router, tvb, offset, -1, FALSE); proto_tree_add_item(tree, hf_freepastry_router_msg_type, tvb, offset, 2, FALSE); } break; case JOIN_PROTOCOL: type_string = val_to_str(type, freepastry_join_msg, ""); if (tree){ proto_tree_add_item_hidden(tree, hf_freepastry_join, tvb, offset, -1, FALSE); proto_tree_add_item(tree, hf_freepastry_join_msg_type, tvb, offset, 2, FALSE); } break; case LEAFSET_PROTOCOL: type_string = val_to_str(type, freepastry_leafset_msg, ""); if (tree){ proto_tree_add_item_hidden(tree, hf_freepastry_leafset_proto, tvb, offset, -1, FALSE); proto_tree_add_item(tree, hf_freepastry_leafset_msg_type, tvb, offset, 2, FALSE); } break; case ROUTINGTABLE_PROTOCOL: type_string = val_to_str(type, freepastry_routingtable_msg, ""); if (tree){ proto_tree_add_item_hidden(tree, hf_freepastry_routingtable, tvb, offset, -1, FALSE); proto_tree_add_item(tree, hf_freepastry_routingtable_msg_type, tvb, offset, 2, FALSE); } break; default: type_string = val_to_str(type, freepastry_commonapi_msg, ""); if (tree){ proto_tree_add_item_hidden(tree, hf_freepastry_commonapi, tvb, offset, -1, FALSE); proto_tree_add_item(tree, hf_freepastry_commonapi_msg_type, tvb, offset, 2, FALSE); } } if (check_col(pinfo->cinfo, COL_INFO)){ col_append_fstr(pinfo->cinfo, COL_INFO, " %s", type_string); } offset += 2; if (has_sender){ if (tree) { offset = decode_nodehandle(tvb, tree, offset, "Sender"); } else { offset = get_node_handle_len(tvb, offset); } } /*Call the FreePastry messages dissector*/ /*We need to read protocol version*/ if (tvb_reported_length_remaining(tvb, offset) >= 1){ /*Save internal data for message dissector*/ sub_message_info = ep_new(sub_message_info_t); sub_message_info->address = address; sub_message_info->type = type; pinfo->private_data = sub_message_info; next_tvb = tvb_new_subset(tvb, offset, -1, -1); // dissector_try_port(subdissector_message_version_table, tvb_get_guint8(tvb, offset), next_tvb, pinfo, tree); dissector_try_port(subdissector_message_version_table, 0, next_tvb, pinfo, tree); } } /** * Compute the size of a FreePastry TCP Message. Needed by the desegmentation feature. * @return the size of the PDU. **/ static guint get_freepastry_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset) { /* That length doesn't include the length of the header field itself (4bytes); * add that in. */ return (guint) (tvb_get_ntohl(tvb, offset) + 4); } /* * Dissect a TCP FreePastry message. Called by the desegmentation feature * TCP fragments are already reassembled (message is complete) */ static void dissect_freepastry_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti = NULL; proto_tree *freepastry_tree = NULL; gint offset = 0; guint32 address; if (check_col(pinfo->cinfo, COL_PROTOCOL)){ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FreePastry"); } if (check_col(pinfo->cinfo, COL_INFO)){ col_clear (pinfo->cinfo, COL_INFO); col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d", pinfo->srcport, pinfo->destport); } address = tvb_get_ntohl(tvb, offset+4); ti = proto_tree_add_item(tree, proto_freepastry, tvb, 0, -1, FALSE); freepastry_tree = proto_item_add_subtree(ti, ett_freepastry); if (tree){ proto_tree_add_item(freepastry_tree, hf_freepastry_msg_size, tvb, offset, 4, FALSE); proto_tree_add_item(freepastry_tree, hf_freepastry_msg_header_address, tvb, offset+4, 4, FALSE); } offset += 8; decode_freepastry_tcp_msg_invariant(tvb, pinfo, freepastry_tree, offset, address); } /** * Save FreePastry data for this conversation: * - ID of the packet related to FreePastry TCP stream header * - True if this session is an AppSocket **/ static void attach_data_to_conversation(conversation_t *conversation, guint32 id, gboolean is_app_stream) { struct freepastry_tcp_stream_data *tcp_stream_data; /* Is there already some data attached to this conversation?*/ tcp_stream_data = conversation_get_proto_data(conversation, proto_freepastry); if (!tcp_stream_data) { tcp_stream_data = se_alloc(sizeof(struct freepastry_tcp_stream_data)); tcp_stream_data->id = id; tcp_stream_data->is_app_stream = is_app_stream; conversation_add_proto_data(conversation, proto_freepastry, tcp_stream_data); } } /** * Dissect a tvbuff that is supposed to contain a FreePastry TCP Message header. * Note: Message size is unknown and can be segmented * @return TRUE if the dissected tvb contained FreePastry data otherwise FALSE. **/ static gboolean dissect_freepastry_tcp_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, conversation_t *conversation) { guint quick_parse_offset = 0; gint epoch_inet_socket_address_len = 0; gboolean next_message_to_parse = FALSE; gboolean is_source_routed = FALSE; gboolean is_app_stream = FALSE; guint32 app_id; /*Check that the header message is complete*/ if (tvb_length(tvb) < 16 ) {/*16 = minimal header message (no source route)*/ /*ask for more bytes*/ pinfo->desegment_offset = 0; pinfo->desegment_len = 16; return FALSE; } if (tvb_get_ntohl(tvb, quick_parse_offset) != PASTRY_MAGIC_NUMBER){ /*It is not a FreePastry stream for sure*/ return FALSE; } quick_parse_offset += 8; if (tvb_get_ntohl(tvb, quick_parse_offset) == HEADER_SOURCE_ROUTE){ is_source_routed = TRUE; quick_parse_offset +=4; do {/*while there are hops (EISA)*/ if (tvb_reported_length_remaining(tvb, quick_parse_offset) < 1){ /*Require more bytes*/ pinfo->desegment_offset = 0; pinfo->desegment_len = quick_parse_offset + 23;/*15+8 = minimal header with one more EISA*/ return FALSE; } epoch_inet_socket_address_len = get_epoch_inet_socket_address_len(tvb, quick_parse_offset); if (tvb_reported_length_remaining(tvb, quick_parse_offset) < (epoch_inet_socket_address_len + 8)){ /*Require more bytes*/ pinfo->desegment_offset = 0; /*epoch_inet_socket_address + direct header + app ID*/ pinfo->desegment_len = quick_parse_offset + epoch_inet_socket_address_len + 8; return FALSE; } quick_parse_offset += epoch_inet_socket_address_len; } while (tvb_get_ntohl(tvb, quick_parse_offset) == HEADER_DIRECT); } app_id = tvb_get_ntohl(tvb, quick_parse_offset + 4); if (app_id != 0x0){ is_app_stream = TRUE; } quick_parse_offset += 8;/*Direct Header + App ID*/ /*The header message is complete!*/ if (conversation == NULL) { /* No conversation, create one */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } attach_data_to_conversation(conversation, pinfo->fd->num, is_app_stream); /*Check if there are some data for the next message in the buffer*/ if (tvb_length(tvb) != (quick_parse_offset + 1)) { next_message_to_parse = TRUE; } /*Here starts the real job*/ if (check_col(pinfo->cinfo, COL_PROTOCOL)){ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FreePastry"); } if(check_col(pinfo->cinfo,COL_INFO)){ col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d New FreePastry socket", pinfo->srcport, pinfo->destport); if (is_source_routed){ col_append_str(pinfo->cinfo, COL_INFO, " (source routed)"); } } if (tree) { proto_item *ti = NULL; proto_tree *freepastry_tree = NULL; gint offset = 0; ti = proto_tree_add_item(tree, proto_freepastry, tvb, 0, -1, FALSE); freepastry_tree = proto_item_add_subtree(ti, ett_freepastry); proto_tree_add_item(freepastry_tree, hf_freepastry_header_magic_number, tvb, offset, 4, FALSE); offset += 4; proto_tree_add_item(freepastry_tree, hf_freepastry_header_version_number, tvb, offset, 4, FALSE); offset += 4; /*is it a source route header or a direct header?*/ if (tvb_get_ntohl(tvb, offset) == HEADER_SOURCE_ROUTE){ proto_tree_add_item(freepastry_tree, hf_freepastry_header_source_route, tvb, offset, 4, FALSE); offset += 4; do { offset = decode_epoch_inet_socket_address(tvb, tree, offset, "Hops"); if (offset == -1){ /*It is a corrupted packet but it is actually a FP packet*/ return TRUE; } } while (tvb_get_ntohl(tvb, offset) == HEADER_DIRECT); } proto_tree_add_item(freepastry_tree, hf_freepastry_header_header_direct, tvb, offset, 4, FALSE); offset += 4; proto_tree_add_uint(freepastry_tree, hf_freepastry_header_app_id, tvb, offset, 4, app_id); offset += 4; } /* Make the dissector for this conversation the non-heuristic FreePastry dissector. */ conversation_set_dissector(conversation, freepastry_tcp_handle); /*TODO Test tvb+offset stuff*/ /*if (next_message_to_parse) { g_warning("There is another message to parse!!!"); tcp_dissect_pdus(tvb+offset, pinfo, tree, freepastry_desegment, 4, get_freepastry_pdu_len, dissect_freepastry_pdu); }*/ return TRUE; } /** * Tag an AppSockets stream **/ static void dissect_freepastry_tcp_app(packet_info *pinfo) { if (check_col(pinfo->cinfo, COL_PROTOCOL)){ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FreePastry"); } if(check_col(pinfo->cinfo,COL_INFO)){ col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d Application Socket", pinfo->srcport, pinfo->destport); } } /** * Dissect a tvbuff containing a FreePastry TCP Message * @return TRUE if the dissected tvb contained FreePastry data otherwise FALSE. **/ static gboolean dissect_freepastry_common_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gboolean result = FALSE; conversation_t *conversation; struct freepastry_tcp_stream_data *tcp_stream_data; conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (conversation == NULL) { result = dissect_freepastry_tcp_header(tvb, pinfo, tree, conversation); } else { tcp_stream_data = conversation_get_proto_data(conversation, proto_freepastry); if (!tcp_stream_data) { /*Should not happen, data is attached just after conversation creation*/ result = dissect_freepastry_tcp_header(tvb, pinfo, tree, conversation); } else if (tcp_stream_data->id == pinfo->fd->num){ /* It is a stream header message */ result = dissect_freepastry_tcp_header(tvb, pinfo, tree, conversation); } else if (tcp_stream_data->is_app_stream){ /* It is an AppSocket */ dissect_freepastry_tcp_app(pinfo); result = TRUE; } else { /* It is a core FreePastry message, activate desegmentation*/ tcp_dissect_pdus(tvb, pinfo, tree, freepastry_desegment, 4, get_freepastry_pdu_len, dissect_freepastry_pdu); result = TRUE; } } return result; } /* * End: TCP FreePastry Core Message dissection. */ /** * Dissect a tvbuff containing a FreePastry UDP Message * (called because we registered a specific port number) **/ static void dissect_freepastry_port_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { dissect_freepastry_common_udp(tvb, pinfo, tree); return; } /** * Dissect a tvbuff containing a FreePastry TCP Message * (called because we registered a specific port number) **/ static void dissect_freepastry_port_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { dissect_freepastry_common_tcp(tvb, pinfo, tree); return; } /** * Heuristically dissect a tvbuff containing a FreePastry UDP Message * @return TRUE if the dissected tvb contained FreePastry data otherwise FALSE. **/ static gboolean dissect_freepastry_heur_udp(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { /*Message is too small*/ if (tvb_length(tvb) < 16 ) { return FALSE; } /*Is it a FreePastry Message?*/ if (tvb_get_ntohl(tvb, 0) != PASTRY_MAGIC_NUMBER){ return FALSE; } dissect_freepastry_common_udp(tvb, pinfo, tree); return TRUE; } /** * Heuristically dissect a tvbuff containing a FreePastry TCP Message * @return TRUE if the dissected tvb contained FreePastry data otherwise FALSE. **/ static gboolean dissect_freepastry_heur_tcp(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { return dissect_freepastry_common_tcp(tvb, pinfo, tree); } void proto_register_freepastry(void) { static hf_register_info hf[] = { { &hf_freepastry_direct, { "Direct messages", "freepastry.direct", FT_NONE, BASE_NONE, NULL, 0x0, "Show only direct access traffic", HFILL }}, { &hf_freepastry_router, { "Router messages", "freepastry.router", FT_NONE, BASE_NONE, NULL, 0x0, "Show only router traffic", HFILL }}, { &hf_freepastry_commonapi, { "Common API messages", "freepastry.commonapi", FT_NONE, BASE_NONE, NULL, 0x0, "Show only common API traffic", HFILL }}, { &hf_freepastry_join, { "Join protocol", "freepastry.join", FT_NONE, BASE_NONE, NULL, 0x0, "Show only join protocol traffic", HFILL }}, { &hf_freepastry_routingtable, { "Routing table maintenance protocol", "freepastry.routingtable", FT_NONE, BASE_NONE, NULL, 0x0, "Show only routing table maintenance protocol traffic", HFILL }}, { &hf_freepastry_leafset_proto, { "Leafset maintenance protocol", "freepastry.leafset_proto", FT_NONE, BASE_NONE, NULL, 0x0, "Show only leafset maintenance protocol traffic", HFILL }}, { &hf_freepastry_liveness, { "Liveness messages", "freepastry.liveness", FT_NONE, BASE_NONE, NULL, 0x0, "Show only liveness traffic", HFILL }}, { &hf_freepastry_msg_size, { "Message size", "freepastry.msg_size", FT_UINT32, BASE_DEC, NULL, 0x0, "Message size", HFILL }}, { &hf_freepastry_eisa_num_add, { "Number of addresses", "freepastry.eisa.num", FT_UINT8, BASE_DEC, NULL, 0x0, "Number of address in an EpochInetSocketAddress", HFILL }}, { &hf_freepastry_eisa_ip, { "IP address", "freepastry.eisa.ip", FT_IPv4, BASE_DEC, NULL, 0x0, "IPv4 address in an EpochInetSocketAddress", HFILL }}, { &hf_freepastry_eisa_port, { "Port number", "freepastry.eisa.port", FT_UINT16, BASE_DEC, NULL, 0x0, "Port number in an EpochInetSocketAddress", HFILL }}, { &hf_freepastry_eisa_epoch, { "Epoch", "freepastry.header.eisa.epoch", FT_UINT64, BASE_DEC, NULL, 0x0, "Epoch in an EpochInetSocketAddress", HFILL }}, { &hf_freepastry_id_type, { "ID type", "freepastry.id_type", FT_INT16, BASE_DEC, VALS(freepastry_id_type), 0x0, "ID type", HFILL }}, { &hf_freepastry_id_value, { "ID value", "freepastry.id", FT_STRING, BASE_NONE, NULL, 0x0, "ID value", HFILL }}, { &hf_freepastry_ringid, { "ID value", "freepastry.ringid", FT_STRING, BASE_NONE, NULL, 0x0, "ID value for ring ID", HFILL }}, { &hf_freepastry_gcid_expiration, { "Expiration", "freepastry.gcid.expiration", FT_UINT64, BASE_DEC, NULL, 0x0, "Expiration for GCID", HFILL }}, { &hf_freepastry_versionkey_version, { "Version", "freepastry.versionkey.version", FT_UINT64, BASE_DEC, NULL, 0x0, "Version number for VersionKey", HFILL }}, { &hf_freepastry_fragmentkey_id, { "Fragment key ID", "freepastry.fragmentkey.id", FT_UINT32, BASE_DEC, NULL, 0x0, "Fragment key ID", HFILL }}, { &hf_freepastry_rs_capacity, { "Capacity", "freepastry.routeset.capacity", FT_UINT8, BASE_DEC, NULL, 0x0, "Capacity of a RouteSet", HFILL }}, { &hf_freepastry_rs_size, { "RouteSet size", "freepastry.routeset.size", FT_UINT8, BASE_DEC, NULL, 0x0, "Size of a RouteSet", HFILL }}, { &hf_freepastry_rs_closest, { "Closest", "freepastry.routeset.closest", FT_UINT8, BASE_DEC, NULL, 0x0, "Index of the closest node in a RouteSet", HFILL }}, { &hf_freepastry_ns_size, { "NodeHandleSet size", "freepastry.nodehandleset.size", FT_UINT8, BASE_DEC, NULL, 0x0, "Size of a NodeSet", HFILL }}, { &hf_freepastry_mns_type, { "Internal Multiring NodeHandleSet type", "freepastry.multiringnodehandleset.type", FT_UINT8, BASE_DEC, NULL, 0x0, "Type for a Multiring NodeHandleSet", HFILL }}, { &hf_freepastry_ls_size, { "Leafset size", "freepastry.leafset.size", FT_UINT8, BASE_DEC, NULL, 0x0, "Size of a leafset", HFILL }}, { &hf_freepastry_ls_num_unique_handle, { "Number of unique handles", "freepastry.leafset.num_unique", FT_UINT8, BASE_DEC, NULL, 0x0, "Number of unique handles in a leafset", HFILL }}, { &hf_freepastry_ls_cw_size, { "Clockwise size", "freepastry.leafset.cw_size", FT_UINT8, BASE_DEC, NULL, 0x0, "Number of NodeHandle inside a clockwise SimilarSet", HFILL }}, { &hf_freepastry_ls_ccw_size, { "Counter clockwise size", "freepastry.leafset.ccw_size", FT_UINT8, BASE_DEC, NULL, 0x0, "Number of NodeHandle inside a counter clockwise SimilarSet", HFILL }}, { &hf_freepastry_ls_handle_index, { "Index", "freepastry.leafset.hdl_index", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_freepastry_header_magic_number, { "Magic number", "freepastry.header.magic_number", FT_UINT32, BASE_HEX, NULL, 0x0, "Magic Number", HFILL }}, { &hf_freepastry_header_source_route, { "Source Route Header", "freepastry.header.sourceroute", FT_UINT32, BASE_HEX, NULL, 0x0, "Source Route Header", HFILL }}, { &hf_freepastry_header_version_number, { "Version number", "freepastry.header.version", FT_UINT32, BASE_DEC, NULL, 0x0, "Protocol version number", HFILL }}, { &hf_freepastry_header_current_hop, { "Hop counter", "freepastry.header.hop_counter", FT_UINT8, BASE_DEC, NULL, 0x0, "Hop counter", HFILL }}, { &hf_freepastry_header_num_hop, { "Number of hops", "freepastry.header.num_hop", FT_UINT8, BASE_DEC, NULL, 0x0, "Number of hops", HFILL }}, { &hf_freepastry_header_source_route_len, { "Source route length", "freepastry.header.source_route_len", FT_UINT16, BASE_DEC, NULL, 0x0, "Size of the virtual link", HFILL }}, { &hf_freepastry_header_header_direct, { "Header direct", "freepastry.header.header_direct", FT_UINT32, BASE_HEX, NULL, 0x0, "Header direct", HFILL }}, { &hf_freepastry_header_app_id, { "Application ID", "freepastry.header.app_id", FT_UINT32, BASE_DEC, NULL, 0x0, "Application ID", HFILL }}, { &hf_freepastry_msg_header_address, { "Address", "freepastry.msg_header.address", FT_UINT32, BASE_HEX, VALS(freepastry_address), 0x0, "The application in the overlay that the message goes to", HFILL }}, { &hf_freepastry_msg_header_has_sender, { "Has sender", "freepastry.msg_header.has_sender", FT_BOOLEAN, 8, NULL, 0x0, "True if the sender of the message is specified", HFILL }}, { &hf_freepastry_msg_header_priority, { "Priority", "freepastry.msg_header.priority", FT_INT8, BASE_DEC, VALS(freepastry_priority), 0x0, "Priority", HFILL }}, { &hf_freepastry_liveness_msg_type, { "Message type", "freepastry.liveness.type", FT_INT16, BASE_DEC, VALS(freepastry_liveness_message), 0x0, "Message type for liveness messages", HFILL }}, { &hf_freepastry_liveness_msg_sent_time, { "Sent", "freepastry.liveness.send_time", FT_UINT64, BASE_DEC, NULL, 0x0, "When a Ping message has been sent", HFILL }}, { &hf_freepastry_router_msg_type, { "Message type", "freepastry.router.type", FT_INT16, BASE_DEC, VALS(freepastry_router_msg), 0x0, "Message type for router messages", HFILL }}, { &hf_freepastry_join_msg_type, { "Message type", "freepastry.join.type", FT_INT16, BASE_DEC, VALS(freepastry_join_msg), 0x0, "Message type for join protocol messages", HFILL }}, { &hf_freepastry_leafset_msg_type, { "Message type", "freepastry.leafset.type", FT_INT16, BASE_DEC, VALS(freepastry_leafset_msg), 0x0, "Message type for leafset maintenance protocol messages", HFILL }}, { &hf_freepastry_routingtable_msg_type, { "Message type", "freepastry.routingtable.type", FT_INT16, BASE_DEC, VALS(freepastry_routingtable_msg), 0x0, "Message type for routing table maintenance protocol messages", HFILL }}, { &hf_freepastry_direct_msg_type, { "Message type", "freepastry.direct.type", FT_INT16, BASE_DEC, VALS(freepastry_direct_access_msg), 0x0, "Message type for direct access messages", HFILL }}, { &hf_freepastry_commonapi_msg_type, { "Message type", "freepastry.commonapi.type", FT_INT16, BASE_DEC, VALS(freepastry_commonapi_msg), 0x0, "Message type for common API messages", HFILL }}, { &hf_freepastry_direct_msg_version, { "Version", "freepastry.direct.msg_version", FT_UINT8, BASE_DEC, NULL, 0x0, "Version for direct access messages", HFILL }}, { &hf_freepastry_router_msg_version, { "Version", "freepastry.router_proto.msg_version", FT_UINT8, BASE_DEC, NULL, 0x0, "Version for routing table maintenance messages", HFILL }}, { &hf_freepastry_commonapi_msg_version, { "Version", "freepastry.commonapi.msg_version", FT_UINT8, BASE_DEC, NULL, 0x0, "Version for common API messages", HFILL }}, { &hf_freepastry_join_msg_version, { "Version", "freepastry.join.msg_version", FT_UINT8, BASE_DEC, NULL, 0x0, "Version for join protocol messages", HFILL }}, { &hf_freepastry_routingtable_msg_version, { "Version", "freepastry.routingtable.msg_version", FT_UINT8, BASE_DEC, NULL, 0x0, "Version for routing table maintenance messages", HFILL }}, { &hf_freepastry_leafset_proto_msg_version, { "Version", "freepastry.leafset_proto.msg_version", FT_UINT8, BASE_DEC, NULL, 0x0, "Version for leafset maintenance messages", HFILL }} }; /* Setup protocol subtree array */ static gint *ett[] = { &ett_freepastry, &ett_freepastry_eisa, &ett_freepastry_isa, &ett_freepastry_nh, &ett_freepastry_rs, &ett_freepastry_ns, &ett_freepastry_ls, &ett_freepastry_ls_cw, &ett_freepastry_ls_ccw }; module_t *freepastry_module; if (proto_freepastry == -1) { proto_freepastry = proto_register_protocol ( "FreePastry Binary Protocol", /* name */ "FreePastry", /* short name */ "freepastry" /* abbrev */ ); } freepastry_module = prefs_register_protocol(proto_freepastry, NULL); prefs_register_bool_preference(freepastry_module, "desegment_freepastry_messages", "Reassemble FreePastry messages spanning multiple TCP segments", "Whether the FreePastry dissector should desegment all messages spanning multiple TCP segments", &freepastry_desegment); proto_register_field_array(proto_freepastry, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); subdissector_message_version_table = register_dissector_table("freepastry.msg", "FreePastry Message", FT_UINT8, BASE_DEC); } void proto_reg_handoff_freepastry(void) { static int Initialized=FALSE; if (!Initialized) { freepastry_udp_handle = create_dissector_handle(dissect_freepastry_port_udp, proto_freepastry); freepastry_tcp_handle = create_dissector_handle(dissect_freepastry_port_tcp, proto_freepastry); dissector_add("udp.port", UDP_PORT_FREEPASTRY, freepastry_udp_handle); dissector_add("tcp.port", TCP_PORT_FREEPASTRY, freepastry_tcp_handle); heur_dissector_add("udp", dissect_freepastry_heur_udp, proto_freepastry); heur_dissector_add("tcp", dissect_freepastry_heur_tcp, proto_freepastry); } }