All pastes #729700 Raw Edit

Someone

public text v1 · immutable
·published 2007-10-08 07:06 UTC
rendered paste body
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 <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