rendered paste bodywinny_info.h
------------
//
// Copyright 2003 Sandvine Incorporated, All rights reserved.
//
#ifndef __WINNY_INFO_H__
#define __WINNY_INFO_H__
// NOTE: Winny version 2.722 detection is done in lengthbased_info.h
#include <protocolRecognition/winny_decryption.h>
#include <protocolRecognition/winny_detect.h>
#include <protocolRecognition/AppProtocolRecognizer.h>
#include <protocolRecognition/ProtocolModulePdbInterfaceInstance.h>
#include <mcd.h>
#include <arcfour.h>
#define MAX_WINNY_LEN 0x20000
#define OPCODE_OFFSET 4
#define MIN_WINNY_OPCODE 0x61
#define MAX_WINNY_OPCODE 0x65
#define OPCODE_WARN_THRESHOLD 0x64 //if opcode >= to this, we will give some kind of warning
#define OPCODE_D 0x64
#define OPCODE_E 0x65
namespace AppProtocol {
// This represents the overall application
class WinnyInfo : public AppProtocolInfo {
public:
WinnyInfo()
: AppProtocolInfo( REC_PRIORITY_MED, // priority
eAppWinny, // id
"Winny", // long name
"winny", // short name
"", // subname
"", // port list
MCD_P2P_WINNY, // MCD
eInspectType_Custom // recognition type
)
{
m_transports=bTransportTcp;
}
};
template<class Iterator>
class WinnyRecognizer : public AppProtocolRecognizer<Iterator> {
typedef typename AppProtocolRecognizer<Iterator>::DataFlow_type DataFlow_type;
public:
WinnyRecognizer ( AppProtocolInfo *in ) :
AppProtocolRecognizer<Iterator>( REC_PRIORITY_MED,
MCD_P2P_WINNY,
&in->m_matchCount,
eTransportTcp )
{
}
// the recognized protocol will be passed back as the MCD code
// and the caller will have to look up the RecognizerInfo class
void matchInitiator( DataFlow_type &input,
RecognitionResult &result )
{
const osiUint8 *begin = input.l5begin;
const osiUint8 *end = input.l5end;
osiUint32 length = end - begin;
if(length < 11) {
result.result = eInspectResult_nomatch;
return;
}
//check if it matches the Winny signature
//check for v2.0b7.2X control packets ( X = 3 to 8 )
if( isWinny728( input, result ) || isWinnyOther( input ) )
{
result.result = eInspectResult_match;
result.mcd = MCD_P2P_WINNY;
result.sub_mcd = MCD_P2P_WINNY;
result.transport_mcd = MCD_P2P_WINNY;
result.stats_mcd = MCD_P2P_WINNY;
result.id = eAppWinny;
(*this->counter)++;
return;
}
//check if it matches the old Winny signature
if (length == 11)
{
Arcfour a;
a.SetKey(begin + 2,4);
unsigned char msgLen[4];
decryptBytes(a, msgLen, begin + 6, 4);
if (readL32(msgLen) + 10 == length )
{
result.result = eInspectResult_match;
result.mcd = MCD_P2P_WINNY;
result.sub_mcd = MCD_P2P_WINNY;
result.transport_mcd = MCD_P2P_WINNY;
result.stats_mcd = MCD_P2P_WINNY;
result.id = eAppWinny;
(*this->counter)++;
return;
}
}
result.result = eInspectResult_nomatch;
}
// server data is ignored
void matchResponder( DataFlow_type &input,
RecognitionResult &result )
{
const osiUint8 *begin = input.l5begin;
const osiUint8 *end = input.l5end;
osiUint32 length = end - begin;
if(length < 11) {
result.result = eInspectResult_nomatch;
return;
}
//check if it matches the v2.0b7.2X signatures
if( isWinny728( input, result ) || isWinnyOther( input ) )
{
result.result = eInspectResult_match;
result.mcd = MCD_P2P_WINNY;
result.sub_mcd = MCD_P2P_WINNY;
result.transport_mcd = MCD_P2P_WINNY;
result.stats_mcd = MCD_P2P_WINNY;
result.id = eAppWinny;
(*this->counter)++;
return;
}
result.result = eInspectResult_nomatch;
}
private:
// function returns true if the packet is a Winny v2.0b7.2X "handshake" packet
bool isWinnyOther( DataFlow_type &input )
{
cWinnyDetect WinnyDetector;
const osiUint8 * data = input.l5begin;
// Address subtraction gives the length in bytes
osiUint32 length = ( input.l5end - input.l5begin );
// TracePrintf( "Length of packet in 7.27 detector: %i", length );
return WinnyDetector.Decrypt( data, length );
}
// returns true if the packet is a Winny v2.0b7.28
// "Handshake" packet (see the Winny spec for details)
bool isWinny728( DataFlow_type &input,
RecognitionResult &result )
{
Winny728Decrypt decryptor;
const osiUint8 *begin = input.l5begin;
TracePrintf("Key: 0x%X", *(osiUint32*)(begin+2));
decryptor.SetKey(begin + 2, 4);
osiUint8 decrypted[5];
decryptBytes(decryptor, decrypted, begin + 6, 5);
osiUint32 lengthField = readL32(decrypted);
TracePrintf("Length: 0x%X Opcode: 0x%X\n", lengthField, (unsigned)decrypted[OPCODE_OFFSET]);
bool retVal = lengthField != 0 && lengthField <= MAX_WINNY_LEN
&& decrypted[OPCODE_OFFSET] >= MIN_WINNY_OPCODE
&& decrypted[OPCODE_OFFSET] <= MAX_WINNY_OPCODE;
if(retVal && decrypted[OPCODE_OFFSET] >= OPCODE_WARN_THRESHOLD)
{
//increment the pdb variable
if(decrypted[OPCODE_OFFSET] == OPCODE_D) {
++(ProtocolModulePdbInterfaceInstance().winnyOpcodeDCount);
} else if(decrypted[OPCODE_OFFSET] == OPCODE_E) {
++(ProtocolModulePdbInterfaceInstance().winnyOpcodeECount);
} else {
//log some kind of error?
}
}
return retVal;
}
void decryptBytes(Arcfour & decryptor,
osiUint8 * dest,
const osiUint8 * src,
unsigned len)
{
for (unsigned i = 0; i < len; ++i)
{
dest[i] = src[i] ^ decryptor.Random();
}
}
};
}
#undef MAX_WINNY_LEN
#undef OPCODE_OFFSET
#undef MIN_WINNY_OPCODE
#undef MAX_WINNY_OPCODE
#undef OPCODE_WARN_THRESHOLD
#undef OPCODE_D
#undef OPCODE_E
#endif