FreePastry/tools/wireshark/packet-freepastry.c

1664 lines
56 KiB
C
Raw Permalink Normal View History

2019-05-13 12:45:05 +00:00
/* packet-freepastry.c
* Routines for the FreePastry Binary protocol
ion
* Copyright 2007, David Dugoujon <dav176fr@yahoo.fr>
*
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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 <gmodule.h>
#include <epan/packet.h>
#include <epan/emem.h>
#include <epan/conversation.h>
#include <epan/dissectors/packet-tcp.h>
#include <epan/prefs.h>
#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, "<Unknown type %d>"));
}
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, "<Unknown type %d>");
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, "<Unknown type %d>");
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, "<Unknown type %d>");
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, "<Unknown type %d>");
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, "<Unknown type %d>");
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, "<Unknown address %d>");
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);
}
}