//this file is part of eMule
//Copyright (C)2006 David Xanatos ( Xanatos@Lycos.at / http://neomule.sourceforge.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#pragma once

#include "MapKey.h"

#define DEF_MSG_FILTER			L"Your client has an infinite queue|Your client is connecting too fast|fastest download speed|ZamBoR|DI-Emule|Join the L33cher|eMule FX|FXeMule|Ketamine|robot from RIAA|te@m projekt|HyperMule|PRO Ultra|fastest eMule|agent from PeerFactor|bot from MPAA|[Sangue-Suga]"
#define	DEF_COM_FILTER			L"http://|https://|ftp://|www.|ftp.|HyperMule|PRO Ultra"
#define I2B(x) ((x) ? true : false)

// Leechers.dat specyfications and file tags
#define DFLT_KNOWNLEECHER_FILENAME _T("leechers.dat")
#define DFLT_KNOWNLEECHER_SIGN_FILENAME _T("leechers.sig")

#define DFLT_DLP_FILENAME _T("dlp.dll")
#define DFLT_DLP_SIGN_FILENAME _T("dlp.sig")

// Tags
#define KL_FORMAT_SEPARATOR		','

#define KL_FORMAT_EX_SEPARATOR	';'

#define KL_OPERATOR_NOT			'!'
#define KL_BEGIN_MARK			':'

#define KL_EXTENDED				'#'

#define KL_TYPE_MOD				'M'
#define KL_TYPE_MODc			'm'
#define KL_TYPE_NICK			'N'
#define KL_TYPE_NICKc			'n'
#define KL_TYPE_SOFTWARE		'S'
#define KL_TYPE_HASH			'H'
#define KL_TYPE_OPCODE			'O'

// Leecher Types
#define KLT_BREAKER				'0'
#define KLT_HARD				'1'
#define KLT_NORMAL				'2'
#define KLT_SOFT				'3'
#define KLT_MOD					'4'

enum ELeecherType{
	LT_NO = 0,	// Its NOT a leecher
	LT_BREAKER,	// GPL breaked
	LT_HARD,	// hard leecher
	LT_NORMAL,	// normal leecher
	LT_SOFT,	// soft leecher
	LT_MOD,		// Bad mod only
};

// OpCode Data
#define OCS_HELLO				'1'
#define OCS_INFO				'2'
#define OCS_PACKET				'3'
#define OCS_PACKET_EX			'4'
#define OCS_PACKET_UDP			'5'
#define OCS_RAW_TCP				'6'
#define OCS_RAW_UDP				'7'

enum EOpcodeProc{
	OC_NULL = 0,
	OC_HELLO,
	OC_INFO,
	OC_PACKET,
	OC_PACKET_EX,
	OC_PACKET_UDP,
	OC_RAW_TCP,
	OC_RAW_UDP,
	OC_SUBOPCODE
};

struct TOpCode{
	uint8			OpCode;
	EOpcodeProc		OpSource;
	uint32			OpValue;
};


// Queue entries for Test
struct TTestClient{
	uint32		IP;
	CString		strNick;
	CString		strMod;
	CString		strSoft;
	uchar		abyHash[16];
	TOpCode*	OpCode;
	BOOL		Confirm;	// If the client has an active argos state send also an answer when no result found
};

// Result Answers
#define MSG_LEECHER_FOUND		1
#define MSG_LEECHER_NOT_FOUND	2

enum ELeecherIdent{
	IT_NO = 0,	// Its NOT a leecher
	IT_MOD,		// Is a leecher identified by Mod String
	IT_NICK,	// Is a leecher identified by Nick Name
	IT_SOFTWARE,// Is a leecher identified by Software
	IT_HASH,	// Is a leecher identified by hash
	IT_OPCODE	// Is a leecher identified by opcode
};

struct TLeecherInfo{
	ELeecherType	LeecherType;
	ELeecherIdent	Identified;
	BOOL			IdentifiedEx;
	CString			Comment;
	UINT			DetectionLevel;
	TOpCode			DetectedOpCode;
};

struct TArgosResult{
	uint32			IP;
	TLeecherInfo	Info;
};

// Known leecher
enum ETestStr{
	TS_NULL = 0,
	TS_MOD,
	TS_MODc,
	TS_NICK,
	TS_NICKc,
	TS_SOFTWARE,
	TS_HASH
};

struct TLString{
	ETestStr		Test;
	CString			String;
	bool			Operator;
};
typedef CList<TLString> CExStrList;

struct TKnownLeecher{
	ETestStr		Test;
	CString			String;
	CExStrList*		Extra;
	TLeecherInfo	Info;
};

struct TLeecherOpcode{
	TOpCode			OpCode;
	CExStrList*		Extra;
	TLeecherInfo	Info;
};

// Statistic
struct TLeecherStatistic{
	uint32			Level1Hits;
	uint32			Level2Hits;
	uint32			Level3Hits;
};

// Detection Reasons
enum EArgosReason{
	AR_NULL = 0,
// This flags are set by scanner engine and dlp library
	AR_LEECHERMOD,
	AR_LEECHERNICK,
	AR_LEECHEROPCODE,		// (*)
	AR_LEECHERHASH,

// This flags are set by behavior analysis:
	AR_NICKTHIEF,			// Users that mirrors our nick
	AR_MODTHIEF,			// Users that mirrors our mod version
	AR_HASHTHIEF,			// Users that mirrors the hash of someone
	AR_CREDITHACK,			// He uses our hash !
	AR_HASHCHANGED,			// Client have changed his hash (*)
	AR_GHOSTMODE,			// Mods that uses protocol extensions but does not send an mod string (*)
	AR_FAKECLIENT,			// Mods that trying to fake an other client eDonkey/hybride or whatever
	AR_AGRESSIV,			// Clients that reask for download to fast (*)
	AR_FILESCANNER,			// Clients that ask to often for files we don't have (*)
	AR_FILEFAKER,			// Clients that answers with FNF while having the file (*)
	AR_CORRUPTEDSENDER,		// Clients Identified as sender of corrupt data (*)
	AR_RANKFLOODER,			// Clients that sands to us Queue rankings without being asked (*)
	AR_FAILED,				// Client that fails some upload sessions, may be bogus or some kind of leecher or just have network problems, anyway filter him out
	AR_XSEXPLOIT,			// Client abuses XS or don't answer requests while asking
	AR_NICKCHANGER,			// Client that change to often the nick name
	AR_MODCHANGER,			// Client that change to often the mod string
	AR_NULLNICK,			// Client that sends a NULL nick name
	AR_SPAM,				// Client is sending known spam
	AR_BADHELLO, 			// Client send a suspect hello packet
	AR_BADPROT				// Client have violated the protocol in a way known to be used by leechers for identification
};

// (*) - Unban via timeout

struct TArgosClient{
	// using bitfield to save some bytes, it stores the reason(s) why the mod is a bad one
	UINT
			m_bArgosIsLeecherMod		: 1,
			m_bArgosIsLeecherOpCode		: 4,
			m_bArgosIsLeecherNick		: 1,
			m_bArgosIsLeecherHash		: 1,
			m_bArgosIsNickThief			: 1,
			m_bArgosIsModThief			: 1,
			m_bArgosIsHashThief			: 2, // Can be detected via Trust (01) or when we have a connected SUI (10)
			m_bArgosIsCreditHack		: 1,
			m_bArgosIsHashChanged		: 2, // Can be directly detected (01) or found in track list (10)
			m_bArgosIsGhostMode			: 1,
			m_bArgosIsFakeClient		: 2, // Faked software by protocol analysis (01) or software listed as fake (10)
			m_bArgosIsAgressiv			: 2,
			m_bArgosIsFileScanner		: 1,
			m_bArgosIsFileFaker			: 1,
			m_bArgosIsCorruptedSender	: 1,
			m_bArgosIsRankFlooder		: 1,
			m_bArgosIsFailed			: 1,
			m_bArgosIsXSExploit			: 2, // can be to fast ask (01) or disabled answer (10)
			m_bArgosIsNickChanger		: 1,
			m_bArgosIsModChanger		: 1,
			m_bArgosIsNullNick			: 1,
			m_bArgosIsSpam				: 2; // can be message spam (01) or comment spam (10)
										// :1 left
	uchar
			m_bArgosIsBadHello			: 5, // can be (00001) exrta bytes, or (00010) Bad order, or (00100) bad tag type, or (01000) bad port, or (10000) emcrypt
			m_bArgosIsBadProt			: 2; // can be (01) bad hash size, or (10) bad start upload request
										// :1 left
	uint8	m_uLeecherOpCode;

	// Some events may have different ban times but relevant will be only the longest
	// lower states will be kept until timeout of the hardest crime...
	// This is not so nice but we don't care about leechers,
	// I don't want have 24Bytes per client wasted tor the timers, 4 are enough
	// Btw: the other states have no timeout they will be verified from time to time...
	uint32	m_uLastDetectionTime;

	// this is for the cleanup function
	uint32	m_uLastSeenTime;

	// Leecher type detected via ModString Nick or opcode
#ifdef _DEBUG
	ELeecherType m_eLeecherType;
#else
	uint8 m_eLeecherType;
#endif

	// Leecher handling Restrictions
	uint8	m_uPunishment;

	// Comment from Leechers.dat
	CString* Comment;
};

// Trust Test
struct TArgosTrust{
	uint32	m_nTrustedTransfer;
	uint8	m_nTrust;
	uint32	m_uLastTransferTime;
};

class CArgos: public CWinThread
{
public:
	CArgos();
	~CArgos();

	uint32	GetArgosCount()	{ return m_ArgosList.GetCount();}

	void	Process();

	void	DoArgos(uint32 dwIP, EArgosReason Reason, ELeecherType LeecherType, CString Comment = _T(""), EOpcodeProc uOpSource = OC_NULL, uint8 uOpCode = NULL);
	void	DoArgos(uint32 dwIP, EArgosReason Reason, UINT Flag1 = NULL);
	void	UnArgos(uint32 dwIP, EArgosReason Reason, UINT Flag1 = NULL);
	bool	IsArgos(uint32 dwIP, bool bMod = false);
	bool	IsArgos(uint32 dwIP, EArgosReason Reason, UINT Flag1 = NULL);
	float	GetPunishment(const CUpDownClient* Client);

	uint32	GetTrust(uint32 dwIP);
	void	AddTrustedTransfer(uint32 dwIP, uint32 nTransferred);

	void	CheckClient(CUpDownClient* Client, bool bNotOfficial = false, bool bInfo = false);

	void	SUIPassed(CUpDownClient* Client);

	CString	GetAntiNickThiefNick();

	void	LoadFincanHashes();

	// Scanner Engine:
	void	AddClientToTest(CUpDownClient* Client, TOpCode* OpCode = NULL);
	void	AddClientToTest(uint32 dwIP, TOpCode* OpCode = NULL);

	bool	LoadFileInfo(LPCTSTR Path, int &Version, double &RevisionDate, CString* Autor = NULL);
	int		LoadFromFile();
	void	RemoveAllKnownLeechers();

	// DLP
	bool	LoadDLPlibrary();
	void	UnLoadDLPlibrary();

	void	LogIdentifiedLeecher(TArgosResult* ArgosResult);
	CString GetDefaultFilePath(bool bSig = false) const;
	CString GetDefaultFilePathDLP(bool bSig = false) const;
	void	UpdateLeecherList();

	CString	GetArgosString(const CUpDownClient* Client, bool bShort = false);

	void	GetStatistics(int stats[26]);

	void	EndThread();

protected:
	friend class CClientArgosInfoPage;

	TArgosClient*	AddArgosClient(uint32 dwIP);
	void			RemoveArgosClient(uint32 dwIP, bool bTrust = false);
	TArgosClient*	GetArgosClient(uint32 dwIP);

	bool	IsArgos(TArgosClient* Client, bool bMod = false);

	float	GetCompensation(const CUpDownClient* Client);
	bool	IsNullCompensation(const CUpDownClient* Client);

	void	ResetTrusted(uint32 dwIP);

	void	CalcPunishment(TArgosClient* Client, uint32 dwIP);

	void	ArgosCheckSoftware(CUpDownClient* Client);
	void	ArgosCheckModification(CUpDownClient* Client, bool bNotOfficial = true);
	void	CheckForNickThief(CUpDownClient* Client);
	void	CheckForModThief(CUpDownClient* Client);
	bool	CheckForFincanHash(TTestClient* Client);

	// DLP
	TLeecherInfo* PerformDLPCheck(TTestClient* TestClient);

	// Info System:
	CString GetIdentTypeStr(ELeecherIdent Type);
	CString GetLeecherTypeStr(ELeecherType Type);
	CString GetClientNickSoft(const uint32 uIP) const;

private:
	bool	LoadSignaturFile();

	// DLP
	bool	VerifyDLPSignatur();

	void	ClearTrustList();
	void	RemoveAllArgosClients();

	void	ArgosTrust(uint32 dwIP);

	// Scanner Engine
	static UINT RunProc(LPVOID pParam);
	UINT	RunInternal();

	TLeecherInfo* PerformListCheck(TTestClient* TestClient);
	bool	TestExtra(CExStrList* Extra, TTestClient* TestClient);

	// Notify functions 
	void	LeecherFound(TArgosResult* ArgosResult);
	void	LeecherNotFound(uint32 dwIP);

	// File Interpreter Functions
	ELeecherType GetLeecherType(TCHAR LeecherType);
	ETestStr GetTestType(TCHAR Type);
	ELeecherIdent GetIdentType(TCHAR Type);
	EOpcodeProc GetOpSource(TCHAR OpSource);

	void	CreateAntiNickThiefTag();

	// Known Leecher lists
	CMap <CSKey, const CSKey&, TCHAR, TCHAR> HashMap; 
	CList<TKnownLeecher*>	KnownLeechers;
	CList<TLeecherOpcode*>	KnownLeecherOpcodes;

	// Fincan Hashlist
	CStringList m_FincanHashList;

	// Test queue
	CTypedPtrList<CPtrList, TTestClient*> m_TestClientQueue;

	// Banned Client List
	CMap<uint32, uint32, TArgosClient*, TArgosClient*> m_ArgosList; 

	// Trust transfer list
	CMap<uint32, uint32, TArgosTrust*, TArgosTrust*> m_TrustList;

	// Timers
	uint32	m_dwLastArgosCleanUp;
	uint32	m_dwLastTrustCleanUp;

	// Nick Tag
	CString m_sAntiNickThiefTag;

	// Thread handling
	CCriticalSection threadLocker;
	CCriticalSection QueueLocker;

	CEvent* threadEndedEvent;
	bool doRun;

	// DLP
	HINSTANCE m_dlpInstance;

	typedef uint32 (__cdecl *DLPGETVERSION)();
	typedef bool (__cdecl *DLPINITIALISE)(UINT preferences, void(*log)(int,CString));
	typedef TArgosResult (__cdecl *DLPCHECKCLIENT)(CString strNick, CString strMod, CString strSoft, unsigned char abyHash[16], TOpCode* Opcode, UINT uIP);
	DLPCHECKCLIENT m_dlpCheckClient;

	// statistic
	TLeecherStatistic Statistic;
};

//////////////////////////////////////////////////////////////////////////////////////////////
// Leecher Detection signing authorities
//

const struct sSignatureAuthority{
	TCHAR Authority[10];
	byte PublikKey[160];
} SignatureAuthorityList[3] = 
{
	// Signing Authority David Xanatos 
	'X','a','n','a','t','o','s','\0','\0','\0', 
	48, 129, 157, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 
	1, 5, 0, 3, 129, 139, 0, 48, 129, 135, 2, 129, 129, 0, 200, 
	171, 14, 111, 220, 3, 16, 175, 79, 17, 6, 78, 180, 51, 183, 
	114, 176, 34, 253, 166, 182, 181, 14, 94, 137, 208, 45, 79, 
	210, 42, 10, 33, 245, 77, 238, 167, 103, 147, 110, 100, 179, 
	214, 5, 164, 117, 8, 9, 13, 194, 224, 27, 89, 68, 39, 180, 
	225, 42, 180, 108, 87, 190, 35, 39, 250, 168, 35, 28, 123, 
	4, 172, 14, 90, 24, 154, 223, 212, 251, 43, 56, 93, 95, 192, 
	3, 231, 62, 238, 65, 103, 186, 45, 194, 216, 216, 59, 93, 51, 
	109, 172, 138, 251, 45, 48, 130, 222, 133, 37, 112, 13, 20, 
	10, 58, 172, 210, 44, 67, 68, 58, 71, 188, 150, 240, 219, 
	109, 253, 253, 133, 241, 53, 2, 1, 17, 

	// Signing Authority Owen Burnett 
	'O','w','e','n','\0','\0','\0','\0','\0','\0', 
	48, 129, 157, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 
	1, 5, 0, 3, 129, 139, 0, 48, 129, 135, 2, 129, 129, 0, 189, 
	161, 80, 44, 182, 217, 231, 37, 254, 137, 17, 194, 132, 253, 
	133, 182, 78, 97, 154, 16, 221, 216, 46, 170, 12, 25, 15, 173, 
	38, 152, 192, 202, 66, 4, 22, 84, 122, 78, 112, 177, 224, 19, 
	252, 90, 164, 205, 209, 246, 93, 22, 41, 187, 32, 2, 5, 237, 
	57, 127, 23, 137, 84, 46, 132, 187, 9, 249, 153, 206, 84, 167, 
	1, 240, 129, 165, 99, 178, 133, 17, 50, 171, 0, 42, 215, 124, 
	8, 57, 30, 225, 92, 105, 10, 79, 18, 108, 172, 115, 138, 181, 
	76, 109, 175, 196, 53, 56, 68, 212, 192, 18, 193, 103, 214, 8, 
	76, 198, 39, 200, 84, 194, 41, 148, 191, 122, 180, 57, 17, 188, 
	82, 255, 2, 1, 17, 

	// Signing Authority Jan van Achterin
	'A','c','h','t','e','r','i','n','\0','\0',   
	48, 129, 157, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 
	1, 5, 0, 3, 129, 139, 0, 48, 129, 135, 2, 129, 129, 0, 187, 
	191, 128, 191, 223, 183, 226, 237, 88, 201, 97, 29, 162, 206, 
	27, 134, 232, 49, 95, 233, 127, 93, 171, 122, 155, 153, 178, 
	185, 204, 205, 97, 114, 199, 202, 61, 194, 118, 170, 199, 93, 
	44, 197, 71, 20, 228, 149, 199, 19, 25, 0, 25, 111, 227, 85, 
	147, 33, 120, 3, 17, 137, 132, 237, 219, 223, 138, 220, 166, 
	190, 46, 115, 189, 57, 193, 41, 68, 14, 10, 227, 237, 218, 
	126, 6, 126, 92, 185, 239, 89, 18, 242, 137, 96, 90, 193, 
	122, 52, 17, 165, 28, 1, 84, 186, 243, 93, 21, 38, 185, 91, 
	82, 229, 143, 44, 241, 119, 73, 56, 84, 242, 217, 170, 25, 
	70, 80, 99, 245, 20, 249, 173, 9, 2, 1, 17,  
};
