winny_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 #include #include #include #include #include #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 WinnyRecognizer : public AppProtocolRecognizer { typedef typename AppProtocolRecognizer::DataFlow_type DataFlow_type; public: WinnyRecognizer ( AppProtocolInfo *in ) : AppProtocolRecognizer( 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