搞网络开发的时候,涉及到很多私有协议。方便是方便,不过抓包分析问题就麻烦了,wireshark是不可能会为我们自己的网络协议开发分析工具的,唯有自己开发协议分析插件。在私有协议方面,google protobuf是一个类似与IDL的语言,用于定义消息接口,并且支持很多语言,原生支持C++、Java和python,而且还有很多第三方的支持,基本上支持C、C#、object-c,AS3,PHP等.目前protobuf的解析并不是wireshark内置支持的,不排除以后的版本会支持。当前网络上有一个工程可以支持protobuf的解析(protobuf-wireshark),但是该插件原生支持的只有linux版本,而且还只支持UDP解析。经本人改造,已经可以支持windows,并且同时支持TCP和UDP解析。TCP时,需要在protobuf之上加上一个4字节的数据长度,用于支持后续的protobuf消息的大小。
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
消息长度 protobuf二进制消息内容
消息长度的值只包含protobuf消息的大小,不包含自己4个字节的长度。例如protobuf长度为12字节时, 消息长度里面的值,应该是 00 00 00 0c,总的数据长度为16个字节.(如果无法解析数据长度,调换一下网络字节序)
另外对protobuf消息的定义也有一定的限制,必须有一个顶层的消息,例如Message1 和Message2如果是并列的消息,需要有一个Message来包含Message1和Message2.
【配置】
protobuf的配置文件放在C:\Program Files\Wireshark\protobuf目录下面,C:\Program Files\Wireshark\为wireshark在电脑上的安装目录。protobuf文件夹默认是没有的,自己创建。
把附件 *.proto;*.conf放在protobuf目录下面,把dll放在plugins\1.8.6目录下面。
protobuf-wireshark 插件下载, 测试包下载
插件代码:(代码基于google 上面的protobuf-wireshark 修改)
packet-protobuf.h
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include
#include
#include
#include
#include
#include
#include
#include
/* TCP数据包的固定头大小*/
#define FRAME_HEADER_LEN 4
void proto_register_protobuf();
void proto_reg_handoff_protobuf();
static void dissect_protobuf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
static void dissect_protobuf_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
/* Define version if we are not building ethereal statically */
#ifndef ENABLE_STATIC
G_MODULE_EXPORT const gchar version[] = "0.0";
#endif
static int proto_protobuf = -1;
static dissector_handle_t protobuf_handle;
// Protocol field variables - START
static int hf_protobuf = -1;
// Protocol field variables - END
int wireshark_pb_process_protobuf(void *tree_root, int srcport, int dstport, int item_id, void *tvb, void *buf, int buf_size);
void wireshark_pb_process_protobuf_register_proto( int proto, const char* dirname );
void wireshark_pb_process_protobuf_register_ports();
void wireshark_pb_process_protobuf_register_subtree( int proto, const char* name,
int *handle, int ** tree_handle );
void wireshark_pb_process_protobuf_register_field( int proto, int type,
const char* name, const char * fullName,
int *handle );
/* Register plugin - START */
#ifndef ENABLE_STATIC
G_MODULE_EXPORT void
plugin_register(void) {
/* register the new protocol, protocol fields, and subtrees */
if (proto_protobuf == -1) { /* execute protocol initialization only once */
proto_register_protobuf();
}
}
G_MODULE_EXPORT void
plugin_reg_handoff(void){
proto_reg_handoff_protobuf();
}
#endif
void proto_register_protobuf(void) {
module_t *protobuf_module;
char* dirname;
if (proto_protobuf == -1) {
proto_protobuf = proto_register_protocol (
"protobuf ",/* name */
"protobuf",/* short name */
"protobuf"/* abbrev */
);
}
protobuf_module= prefs_register_protocol(proto_protobuf, proto_reg_handoff_protobuf);
/*char**/ dirname = get_persconffile_path("protobuf", FALSE, FALSE);
if( test_for_directory( dirname ) != EISDIR )
{
/* Although dir isn't a directory it may still use memory */
g_free( dirname );
dirname = get_datafile_path("protobuf");
if( test_for_directory( dirname ) != EISDIR )
{
g_free( dirname );
dirname = NULL;
}
}
wireshark_pb_process_protobuf_register_proto( proto_protobuf, dirname );
}
void proto_reg_handoff_protobuf (void) {
static int Initialized=FALSE;
unsigned int i = 0;
if (!Initialized) {
protobuf_handle = create_dissector_handle(dissect_protobuf, proto_protobuf);
wireshark_pb_process_protobuf_register_ports();
}
}
/* Register plugin - END */
/* 解析一个TCP数据包,wireshark会自动做分包和合并处理,此数据是一个完成的数据包,包含包头的内容*/
static void dissect_protobuf_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
/* TODO: implement your dissecting code */\
if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
col_set_str(pinfo->cinfo, COL_PROTOCOL, "protobuf-tcp");
}
/* Clear out stuff in the info column */
if(check_col(pinfo->cinfo,COL_INFO)){
col_clear(pinfo->cinfo,COL_INFO);
}
if (tree) { /* we are being asked for details */
/* Always make sure that offset is LESS than maxOffset */
gint data_len = tvb_get_ntohl(tvb, 0);
proto_item * ti = NULL;
tvbuff_t * next_tvb = tvb_new_subset_remaining (tvb,4);
gint maxOffset = tvb_length(next_tvb);
ti = proto_tree_add_item(tree,proto_protobuf,tvb,0,4,ENC_NA);
proto_item_append_text(ti, ", Length %d",data_len);
wireshark_pb_process_protobuf((void *) tree, pinfo->srcport, pinfo->destport, hf_protobuf,
(void *)next_tvb, (void *)tvb_get_ptr(next_tvb,0,data_len), data_len);
}
}
/* TCP数据包的总长度,包含包头长度 */
static guint get_protobuf_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
{
/* TODO: change this to your needs */
return (guint)tvb_get_ntohl(tvb, offset)+4; /* e.g. length is at offset 4 */
}
/* Generate the main dissector function - START */
static void dissect_protobuf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
if( pinfo->tcp_tree == NULL) //进入解析UDP数据包
{
dissect_protobuf_udp(tvb,pinfo,tree);
}else
{
// 进入解析TCP数据包。
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, FRAME_HEADER_LEN,
get_protobuf_message_len, dissect_protobuf_message);
}
}
static void dissect_protobuf_udp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
col_set_str(pinfo->cinfo, COL_PROTOCOL, "protobuf-udp");
}
/* Clear out stuff in the info column */
if(check_col(pinfo->cinfo,COL_INFO)){
col_clear(pinfo->cinfo,COL_INFO);
}
if (tree) { /* we are being asked for details */
/* Always make sure that offset is LESS than maxOffset */
gint maxOffset = tvb_length(tvb);
wireshark_pb_process_protobuf((void *) tree, pinfo->srcport, pinfo->destport, hf_protobuf,
(void *)tvb, (void *)tvb_get_ptr(tvb,0,maxOffset), maxOffset);
}
} //dissect_protobuf_udp
/* Generate the main dissector function - END */
/** Called from PB to add msg_str to tree_root */
int wireshark_pb_add_protobuf(void* tree_root, void* tvb, int item_id, char* msg_str) {
proto_tree_add_none_format ((proto_tree *) tree_root, item_id, (tvbuff_t*) tvb, 0, -1, msg_str);
return 0;
}
void wireshark_pb_process_protobuf_register_subtree( int proto, const char* name,
int *handle, int ** p_tree_handle )
{
hf_register_info message_info =
{ handle,
{ (char*)name,
(char*)name,
FT_NONE,
BASE_NONE,
NULL, 0,
"",
HFILL
}
};
hf_register_info *hf_info = malloc(sizeof( hf_register_info ) );
*hf_info = message_info;
proto_register_field_array( proto, hf_info, 1 );
proto_register_subtree_array( p_tree_handle, 1 );
}
void wireshark_pb_process_protobuf_register_field( int proto, int type,
const char* name, const char * fullName,
int *handle )
{
int base = ( ( type == FT_UINT32 ) || ( type == FT_UINT64 ) ) ? BASE_HEX :
( ( type == FT_INT32 ) || ( type == FT_INT64 ) ) ? BASE_DEC :
BASE_NONE;
hf_register_info message_info =
{ handle,
{ (char*)fullName,
(char*)name,
type,
base,
NULL, 0,
"",
HFILL
}
};
hf_register_info *hf_info = malloc(sizeof( hf_register_info ) );
*hf_info = message_info;
proto_register_field_array( proto, hf_info, 1 );
}
void wireshark_pb_process_protobuf_dissector_add( const char* name, int port )
{
dissector_add( name, port, protobuf_handle );
}
#include "wireshark-glue-protobuf.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace google;
using namespace protobuf;
using namespace internal;
extern "C" {
static HandleMap* handleMap = NULL;
static MessageConfigList messageConfigList;
static google::protobuf::compiler::Importer* importer = NULL;
static void * _tvb = NULL;
static const char ARRAY_FORMAT[] = "%s[%d]";
/**
* @param buf The message contents
* @param buf_size The length of message contents in buf
* @param tree_root The WireShark tree to which this message is to be added.
* @param item_id Internal wireshark id to refer to this FT_NONE datatype.
*/
int wireshark_pb_process_protobuf(proto_tree* tree_root, int srcport, int dstport, int item_id, tvbuff_t* tvb, void* buf, int buf_size)
{
for( MessageConfigList::iterator it = messageConfigList.begin(); it != messageConfigList.end(); it++ )
{
if( (*it)->matchesSrcPort( srcport ) ||
(*it)->matchesDestPort( dstport ) )
{
return (*it)->dissect( tree_root, item_id, tvb, buf, buf_size );
}
}
DBG_ERR("Failed to find match");
wireshark_pb_add_protobuf(tree_root,tvb,item_id,"Failed to find match");
return -1;
}
void wireshark_pb_process_protobuf_register_subtree_( int proto,
const std::string& name,
const std::string& full_name )
{
Handles *handles = new Handles();
wireshark_pb_process_protobuf_register_subtree( proto,
name.c_str(),
&(handles->handle), &(handles->tree_handle) );
handleMap->insert( StringHandlePair( full_name, handles ) );
}
int wireshark_pb_process_protobuf_get_type( FieldDescriptor::CppType type )
{
struct ftmap_t
{
FieldDescriptor::CppType cpp_type;
ftenum fttype;
int length;
};
static ftmap_t ftmap[] = {
{ FieldDescriptor::CPPTYPE_UINT32, FT_UINT32 },
{ FieldDescriptor::CPPTYPE_INT32, FT_INT32 },
{ FieldDescriptor::CPPTYPE_UINT64, FT_UINT64 },
{ FieldDescriptor::CPPTYPE_INT64, FT_INT64 },
{ FieldDescriptor::CPPTYPE_DOUBLE, FT_DOUBLE },
{ FieldDescriptor::CPPTYPE_FLOAT, FT_FLOAT },
{ FieldDescriptor::CPPTYPE_BOOL, FT_BOOLEAN },
{ FieldDescriptor::CPPTYPE_ENUM, FT_INT32 },
{ FieldDescriptor::CPPTYPE_STRING, FT_STRING } };
for( int i =0; i < sizeof(ftmap)/sizeof(ftmap_t); i++ )
{
if( ftmap[i].cpp_type == type )
{
return ftmap[i].fttype;
}
}
DBG_ERR( "Couldnt find type for cpp type " << type );
return FT_NONE;
}
void wireshark_pb_process_protobuf_register_ports()
{
for( MessageConfigList::iterator it = messageConfigList.begin(); it != messageConfigList.end(); it++ )
{
(*it)->register_ports();
}
}
void wireshark_pb_process_protobuf_register_proto( int proto, const char* dirname )
{
if( dirname == NULL )
{
DBG_ERR( "couldnt get dirname ");
return;
}
DIR* dir = opendir( dirname );
if( dir == NULL )
{
DBG_ERR( "couldnt open " << dirname );
return;
}
dirent* dp;
std::string configFileExtension( ".conf" );
std::string protoFileExtension( ".proto" );
while( ( dp = readdir( dir ) ) != NULL )
{
std::string filename( dp->d_name );
size_t i = filename.rfind( configFileExtension );
if( ( i != std::string::npos ) && ( i == filename.length() - configFileExtension.length() ) )
{
protobuf_MessageConfig* messageConfig = new protobuf_MessageConfig( filename, dirname );
if( messageConfig->isValid() )
{
messageConfigList.push_back( messageConfig );
messageConfig->register_proto( proto );
}
}
//const FileDescriptor* fileDesc = importer->Import( filename );
//
//for( int i = 0; i < fileDesc->message_type_count(); i++ )
//{
// const Descriptor* desc = fileDesc->message_type( i );
// std::string configFileName = desc->name() + ".config";
//
// // check if desc->name() | .config exists TBD
// messageConfigList.push_back( new protobuf_MessageConfig( configFileName, desc ) );
//}
}
closedir( dir );
}
protobuf_Dissector::protobuf_Dissector()
: _leaf( NULL ),
_len( -1 ),
_message( NULL ),
_offset( 0 ),
_prefix_len( -1 ),
_reflection( NULL )
{
}
protobuf_Dissector::protobuf_Dissector( proto_tree* tree, int offset,
const Message* message,
const FieldDescriptor* field,
int index )
: _leaf( NULL ),
_len( -1 ),
_message( message ),
_offset( offset ),
_prefix_len( 0 ),
_reflection( _message->GetReflection() )
{
bool is_root = ( field == NULL );
const std::string& label = ( is_root ) ? _message->GetDescriptor()->name() : field->name();
const std::string& fullname = _message->GetDescriptor()->full_name();
int data_size = _message->ByteSize();
int total_size = data_size;
// if not root field then prefix_len needs to be computed
if( !is_root )
{
_prefix_len = WireFormat::TagSize( _message->GetDescriptor()->index(),
FieldDescriptor::TYPE_MESSAGE );
_prefix_len+= io::CodedOutputStream::VarintSize32( data_size );
total_size+= _prefix_len;
}
_len = total_size;
// construct subtree here itself rather than in dissect method otherwise
// all repeated fields and messages are pushed to end of current tree
// regardless of their current position
HandleMap::iterator it = handleMap->find( fullname );
if( it == handleMap->end() )
{
DBG_ERR( "couldnt find handle for " << fullname );
return;
}
Handles *handles = it->second;
// add a subtree for current message
proto_item* item;
if( index == -1 )
{
item = proto_tree_add_none_format( tree, handles->handle, _tvb,
_offset, _len,
label.c_str() );
}
else
{
item = proto_tree_add_none_format( tree, handles->handle, _tvb,
_offset, _len, ARRAY_FORMAT,
label.c_str(), index );
}
_leaf = proto_item_add_subtree( item, *(handles->tree_handle) );
}
void protobuf_Dissector::dissect( DissectorList& dissectorList )
{
//DBG( "Dissecting " << _message->GetDescriptor()->name()
// << " of length " << _len
// << " prefix len " << _prefix_len );
if( !_leaf )
{
DBG_ERR( "Couldnt find leaf node for current message" );
return;
}
_offset+= _prefix_len;
// now loop through all the field in current message
FieldDescriptorList fields ;
_reflection->ListFields( *_message, &fields );
for( FieldDescriptorList::iterator it = fields.begin(); it!=fields.end(); it++ )
{
const FieldDescriptor* field = *it;
bool is_message = ( field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ) ;
if( field->is_repeated() )
{
if( field->options().packed() )
{
int data_size = WireFormat::FieldDataOnlyByteSize( field, *_message );
if (data_size > 0)
{
_offset += WireFormat::TagSize( field->number(), FieldDescriptor::TYPE_STRING );
_offset += io::CodedOutputStream::VarintSize32( data_size );
}
}
int size = _reflection->FieldSize( *_message, field );
for( int i = 0; i < size; i++ )
{
if( is_message )
{
const Message& subMessage = _reflection->GetRepeatedMessage( *_message,
field, i );
protobuf_Dissector dissector( _leaf, _offset,
&subMessage, field, i );
dissectorList.push_back( dissector );
_offset+= dissector.messageLength();
}
else
{
dissectRepeatedField( field, i );
}
}
}
else if( is_message )
{
const Message& subMessage = _reflection->GetMessage( *_message, field );
protobuf_Dissector dissector( _leaf, _offset,
&subMessage, field );
dissectorList.push_back( dissector );
_offset+= dissector.messageLength();
}
else // plain simple field. process it immediately
{
dissectField( field );
}
}
}
void protobuf_Dissector::dissectField( const FieldDescriptor* field )
{
int len = WireFormat::FieldByteSize( field, *_message );
//DBG( "Dissecting field " << field->name() << " " << len );
HandleMap::iterator it = handleMap->find( field->full_name() );
if( it == handleMap->end() )
{
DBG_ERR( "Couldnt find handle for " << field->full_name() );
return;
}
Handles *handles = it->second;
const EnumValueDescriptor* enumDesc = NULL;
switch( field->cpp_type() )
{
case FieldDescriptor::CPPTYPE_UINT32:
proto_tree_add_uint( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetUInt32( *_message, field ) );
break;
case FieldDescriptor::CPPTYPE_INT32:
proto_tree_add_int( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetInt32( *_message, field ) );
break;
case FieldDescriptor::CPPTYPE_FLOAT:
proto_tree_add_float( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetFloat( *_message, field ) );
break;
case FieldDescriptor::CPPTYPE_UINT64:
proto_tree_add_uint64( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetUInt64( *_message, field ) );
break;
case FieldDescriptor::CPPTYPE_INT64:
proto_tree_add_int64( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetInt64( *_message, field ) );
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
proto_tree_add_double( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetDouble( *_message, field ) );
break;
case FieldDescriptor::CPPTYPE_BOOL:
proto_tree_add_boolean( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetBool( *_message, field ) );
break;
case FieldDescriptor::CPPTYPE_ENUM:
enumDesc = _reflection->GetEnum( *_message, field );
proto_tree_add_int_format_value( _leaf, handles->handle, _tvb, _offset, len,
enumDesc->number(), "%d ( %s )", enumDesc->number(),
enumDesc->name().c_str() );
break;
case FieldDescriptor::CPPTYPE_STRING:
proto_tree_add_string( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetString( *_message, field ).c_str() );
break;
default:
proto_tree_add_item( _leaf, handles->handle, _tvb, _offset, len, true );
};
_offset+=len;
}
void protobuf_Dissector::dissectRepeatedField( const FieldDescriptor* field, int index )
{
int len = 0;
string scratch;
if( !field->options().packed() )
{
len+= WireFormat::TagSize( field->number(), field->type() );
}
//DBG( "Dissecting field " << field->name() << " " << len );
HandleMap::iterator it = handleMap->find( field->full_name() );
if( it == handleMap->end() )
{
DBG_ERR( "Couldnt find handle for " << field->full_name() );
return;
}
Handles *handles = it->second;
const EnumValueDescriptor* enumDesc = NULL;
switch( field->cpp_type() )
{
case FieldDescriptor::CPPTYPE_UINT32:
if( field->type() == FieldDescriptor::TYPE_FIXED32 )
{
len+= WireFormatLite::kFixed32Size;
}
else
{
len+= WireFormatLite::UInt32Size( _reflection->GetRepeatedUInt32( *_message, field, index ) );
}
proto_tree_add_uint( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetRepeatedUInt32( *_message, field, index ) );
break;
case FieldDescriptor::CPPTYPE_INT32:
if( field->type() == FieldDescriptor::TYPE_SFIXED32 )
{
len+= WireFormatLite::kSFixed32Size;
}
else if( field->type() == FieldDescriptor::TYPE_SINT32 )
{
len+= WireFormatLite::SInt32Size( _reflection->GetRepeatedInt32( *_message, field, index ) );
}
else
{
len+= WireFormatLite::Int32Size( _reflection->GetRepeatedInt32( *_message, field, index ) );
}
proto_tree_add_int( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetRepeatedInt32( *_message, field, index ) );
break;
case FieldDescriptor::CPPTYPE_FLOAT:
len+= WireFormatLite::kFloatSize;
proto_tree_add_float( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetRepeatedFloat( *_message, field, index ) );
break;
case FieldDescriptor::CPPTYPE_UINT64:
if( field->type() == FieldDescriptor::TYPE_FIXED64 )
{
len+= WireFormatLite::kFixed64Size;
}
else
{
len+= WireFormatLite::UInt64Size( _reflection->GetRepeatedUInt64( *_message, field, index ) );
}
proto_tree_add_uint64( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetRepeatedUInt64( *_message, field, index ) );
break;
case FieldDescriptor::CPPTYPE_INT64:
if( field->type() == FieldDescriptor::TYPE_SFIXED64 )
{
len+= WireFormatLite::kSFixed64Size;
}
else if( field->type() == FieldDescriptor::TYPE_SINT64 )
{
len+= WireFormatLite::SInt64Size( _reflection->GetRepeatedInt64( *_message, field, index ) );
}
else
{
len+= WireFormatLite::Int64Size( _reflection->GetRepeatedInt64( *_message, field, index ) );
}
proto_tree_add_int64( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetRepeatedInt64( *_message, field, index ) );
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
len+= WireFormatLite::kDoubleSize;
proto_tree_add_double( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetRepeatedDouble( *_message, field, index ) );
break;
case FieldDescriptor::CPPTYPE_BOOL:
len+= WireFormatLite::kBoolSize;
proto_tree_add_boolean( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetRepeatedBool( *_message, field, index ) );
break;
case FieldDescriptor::CPPTYPE_ENUM:
enumDesc = _reflection->GetRepeatedEnum( *_message, field, index );
len+= WireFormatLite::EnumSize( enumDesc->number() );
proto_tree_add_int_format_value( _leaf, handles->handle, _tvb, _offset, len,
enumDesc->number(), "%d ( %s )", enumDesc->number(),
enumDesc->name().c_str() );
break;
case FieldDescriptor::CPPTYPE_STRING:
len+= WireFormatLite::StringSize( _reflection->GetRepeatedStringReference( *_message, field, index, &scratch ) );
proto_tree_add_string( _leaf, handles->handle, _tvb, _offset, len,
_reflection->GetRepeatedString( *_message, field, index ).c_str() );
break;
default:
proto_tree_add_item( _leaf, handles->handle, _tvb, _offset, len, true );
};
_offset+=len;
}
class ErrorCollector
: public protobuf::compiler::MultiFileErrorCollector
{
// Implementation of MultiFileErrorCollector interface.
void AddError(const string & filename, int line, int column, const string & message)
{
DBG( "Error in file " << filename << " at line/col:" << line << "/" << column
<< message );
}
};
protobuf_MessageConfig::protobuf_MessageConfig()
: _desc( NULL )
{
}
protobuf_MessageConfig::protobuf_MessageConfig( const std::string& filename, const std::string& dirname )
: _desc( NULL )
{
parseConfigFile( filename, dirname );
}
int protobuf_MessageConfig::dissect(proto_tree* tree_root, int item_id, tvbuff_t* tvb, void* buf, int buf_size)
{
DynamicMessageFactory factory;
Message* msg = factory.GetPrototype( _desc )->New();
if (!msg->ParseFromArray((char *) buf, buf_size)) {
wireshark_pb_add_protobuf(tree_root,tvb,item_id,"Failed parse message");
DBG_ERR( "Failed to parse message." );
/*
for (int i=0; i < buf_size; i++) {
printf("%2x ", ((char *)buf)[i]);
}
*/
/*
printf("buf size=%d\n", buf_size);
printf("%s\n\n\n", buf);
*/
return -1;
}
// store tvb for subsequent calls
_tvb = tvb;
int offset = 0;
DissectorList dissectorList;
// we process the message tree breadth wise
dissectorList.push_back( protobuf_Dissector( tree_root, offset, msg, NULL ) );
while ( !dissectorList.empty() )
{
protobuf_Dissector dissector = dissectorList.front();
dissectorList.pop_front();
// this can add further entries to message dissector list
dissector.dissect( dissectorList );
} // while( !dissectorList.empty() )
return 0;
}
void Tokenize(const std::string& str,
std::vector& tokens,
const std::string& delimiters = " ")
{
// Skip delimiters at beginning.
std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
std::string::size_type pos = str.find_first_of(delimiters, lastPos);
while (std::string::npos != pos || std::string::npos != lastPos)
{
// Found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// Skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = str.find_first_of(delimiters, lastPos);
}
}
bool protobuf_MessageConfig::isValid()
{
return ( _desc != NULL );
}
bool protobuf_MessageConfig::matchesDestPort( int port )
{
return matchesPort( _dstPorts, port );
}
bool protobuf_MessageConfig::matchesSrcPort( int port )
{
return matchesPort( _srcPorts, port );
}
bool protobuf_MessageConfig::matchesPort( PortList& portList, int port )
{
for( PortList::iterator it = portList.begin(); it != portList.end(); it++ )
{
if( *it == port ) return true;
}
return false;
}
void protobuf_MessageConfig::parseConfigFile( const std::string& filename, const std::string& dirname )
{
std::ifstream infile;
infile.open( ( dirname + "/" + filename ).c_str() );
if( infile.fail() )
{
DBG_ERR( "Failed to open " << filename << "in dir " << dirname );
return;
}
std::string line;
std::string message_name;
while( !infile.eof() )
{
std::getline( infile, line );
// skip lines beginning with #
if( line[0] == '#' ) continue;
std::vector tokens;
Tokenize( line, tokens, " =" );
//DBG( "Found " << tokens.size() << " tokens" );
// skip lines which have less that 2 tokens
if( tokens.size() < 2 ) continue;
if( tokens[0] == "name" )
{
message_name = tokens[1];
continue;
}
if( tokens[0] == "proto_file" )
{
if( importer == NULL )
{
protobuf::compiler::DiskSourceTree *sourceTree = new protobuf::compiler::DiskSourceTree();
static ErrorCollector* errorCollector = new ErrorCollector();
sourceTree->MapPath( "", dirname );
importer = new protobuf::compiler::Importer( sourceTree, errorCollector );
}
DBG( "filename to import " << tokens[1] );
const FileDescriptor* fileDesc = importer->Import( tokens[1] );
if( fileDesc == NULL )
{
DBG_ERR("Unable to parse " << tokens[1] );
continue;
}
DBG( "searching for message " << message_name );
//for( int i = 0; i < fileDesc->message_type_count(); i++ )
//{
// DBG(" message " << fileDesc->message_type( i )->name() );
//}
_desc = fileDesc->FindMessageTypeByName( message_name );
continue;
}
bool src_port = false;
bool dst_port = false;
bool both_ports = false;
src_port = ( tokens[0] == "src_port" );
dst_port = ( tokens[0] == "dst_port" );
both_ports = ( tokens[0] == "port" );
for( int i = 1; i < tokens.size(); i++ )
{
int port = atoi( tokens[i].c_str() );
if( src_port || both_ports )
{
_srcPorts.push_back( port );
}
if( dst_port || both_ports )
{
_dstPorts.push_back( port );
}
}
}
infile.close();
if( _desc == NULL )
{
DBG_ERR( "Couldnt get descriptor from " << filename );
_dstPorts.clear();
_srcPorts.clear();
}
}
void protobuf_MessageConfig::register_ports()
{
register_ports( _srcPorts );
register_ports( _dstPorts );
}
void protobuf_MessageConfig::register_ports( PortList& portList )
{
for( PortList::iterator it = portList.begin(); it != portList.end(); it++ )
{
wireshark_pb_process_protobuf_dissector_add( "tcp.port", *it ); // 注册TCP端口,本人添加
wireshark_pb_process_protobuf_dissector_add( "udp.port", *it ); // 注册UDP端口
}
}
void protobuf_MessageConfig::register_proto( int proto )
{
if( handleMap == NULL )
{
handleMap = new HandleMap();
}
DescriptorList messageDescriptorList;
FieldDescriptorList fieldDescriptorList;
// we process the message definition depth first
messageDescriptorList.push_back( _desc );
while( !messageDescriptorList.empty() )
{
const Descriptor* messageDescriptor = messageDescriptorList.back();
messageDescriptorList.pop_back();
DBG( "Register message ( " << messageDescriptor->name() << " )" );
wireshark_pb_process_protobuf_register_subtree_( proto,
messageDescriptor->name(),
messageDescriptor->full_name() );
for( int i = 0; i < messageDescriptor->field_count(); i++ )
{
const FieldDescriptor* fieldDescriptor = messageDescriptor->field( i );
if( fieldDescriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE )
{
messageDescriptorList.push_back( fieldDescriptor->message_type() );
}
else
{
fieldDescriptorList.push_back( fieldDescriptor );
}
}
}
// process all field descriptors at very end
while( !fieldDescriptorList.empty() )
{
const FieldDescriptor* fieldDescriptor = fieldDescriptorList.back();
fieldDescriptorList.pop_back();
Handles *handles = new Handles();
DBG( "Register field ( " << fieldDescriptor->name() << " : " << fieldDescriptor->full_name() << " )" );
wireshark_pb_process_protobuf_register_field( proto,
wireshark_pb_process_protobuf_get_type( fieldDescriptor->cpp_type() ),
fieldDescriptor->name().c_str(),
fieldDescriptor->name().c_str(),
&(handles->handle) );
handleMap->insert( StringHandlePair( fieldDescriptor->full_name(), handles ) );
}
}
}