wireshark protobuf 插件

搞网络开发的时候,涉及到很多私有协议。方便是方便,不过抓包分析问题就麻烦了,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 );
}

wireshark-gule-protobuf.cc 文件

#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 ) );
  }

}

}





你可能感兴趣的:(C/C++/VC)