sv_a2s_fix/main.cpp
2018-05-19 05:20:28 +03:00

251 lines
No EOL
5.5 KiB
C++

#define GAME_DLL
#include "cbase.h"
#include "bitbuf.h"
#include "plugin.h"
#include "glua.h"
#include "chook.h"
typedef struct {
uint16 family;
uint16 port;
uint32 addr;
} ws2_addr;
#define LUA_CALLBACK "onServerQuery"
#define LUA_CALLBACK2 "onClientResponse"
typedef int (__stdcall* SendTo_t)(int,const char*,int,int,void*,int);
DECLARE_PLUGIN(CA2SFix)
public:
virtual bool Load(CreateInterfaceFn,
CreateInterfaceFn);
virtual void Unload();
virtual bool LuaInit(lua_State*);
bool IsResponseAllowed(uint32 naddr,unsigned char req);
bool ProcessResponse(bf_read&,bf_write&,uint32);
bool ProcessLua(bf_read&,bf_write&,uint32);
bool m_bLua;
lua_State* L;
static CHook* s_pSendHook;
static SendTo_t s_SendTo;
END_PLUGIN(CA2SFix,"A2S Fix");
CHook* CA2SFix::s_pSendHook = NULL;
SendTo_t CA2SFix::s_SendTo = NULL;
static int __stdcall SendTo_Hook(int s,const char* buf,
int len,int flags,void* addr,int tolen)
{
static char s_szBuf[1024];
uint32 naddr = ((ws2_addr*)addr)->addr;
if(*(uint32*)buf == 0xFFFFFFFF)
{
if(!s_CA2SFix.IsResponseAllowed(naddr,(unsigned char)buf[4]))
return len;
}
if(*(uint32*)buf == 0xFFFFFFFF && buf[4] == 0x49)
{
memset(s_szBuf,'\0',1024);
bf_read br(buf,len);
bf_write bf(s_szBuf,1024);
if(!s_CA2SFix.ProcessResponse(br,bf,naddr))
return len;
return CA2SFix::s_SendTo(s,(const char*)bf.GetData(),
bf.GetNumBytesWritten(),flags,addr,tolen);
}
return CA2SFix::s_SendTo(s,buf,len,flags,addr,tolen);
}
bool CA2SFix::Load(CreateInterfaceFn engineFn,CreateInterfaceFn)
{
s_pSendHook = new CHook((DWORD)GetProcAddress(
GetModuleHandle("WS2_32.dll"),"sendto"),5);
s_SendTo = (SendTo_t)s_pSendHook
->HookFunction((DWORD)&SendTo_Hook);
m_bLua = (GetModuleHandle("lua502.dll") != NULL);
return true;
}
void CA2SFix::Unload()
{
delete s_pSendHook;
}
bool CA2SFix::LuaInit(lua_State* _L)
{
L = _L;
return true;
}
bool CA2SFix::ProcessResponse(bf_read& br,bf_write& bf,uint32 naddr)
{
bf.WriteLong(br.ReadLong());
bf.WriteByte(br.ReadByte());
br.ReadByte();
bf.WriteByte(7); //Protocol version
if(m_bLua)
{
if(!ProcessLua(br,bf,naddr))
return false;
}
else bf.WriteBitsFromBuffer(&br,br.GetNumBitsLeft());
return true;
}
#define lua_setstring(L,name,s) \
lua_pushstring(L,name); \
lua_pushstring(L,s); \
lua_settable(L,-3)
#define lua_setnumber(L,name,d) \
lua_pushstring(L,name); \
lua_pushnumber(L,(double)d); \
lua_settable(L,-3)
inline const char* lua_getstring(lua_State* L,
const char* name)
{
lua_pushstring(L,name);
lua_gettable(L,-2);
const char* pStr = lua_tostring(L,-1);
lua_pop(L,1);
return pStr;
}
inline int lua_getnumber(lua_State* L,
const char* name)
{
lua_pushstring(L,name);
lua_gettable(L,-2);
int pNum = lua_tonumber(L,-1);
lua_pop(L,1);
return pNum;
}
int _aterror(lua_State* L)
{
return g_pLua502->GetLuaCallbacks()->OnLuaError(L);
}
inline char* addr2str(uint32 naddr)
{
static char szBuf[32] = {0};
unsigned char* ip = (unsigned char*)&naddr;
sprintf(szBuf,"%d.%d.%d.%d",ip[0],
ip[1],ip[2],ip[3]);
return szBuf;
}
bool CA2SFix::IsResponseAllowed(uint32 naddr,unsigned char req)
{
lua_pushcfunction(L,_aterror);
int iHandler = lua_gettop(L);
lua_getglobal(L,LUA_CALLBACK2);
if(lua_isnil(L,-1))
{
lua_pop(L,2);
return true;
}
lua_pushstring(L,addr2str(naddr));
lua_pushnumber(L,req);
lua_pcall(L,2,1,iHandler);
bool bRet = lua_toboolean(L,-1);
lua_pop(L,2);
return bRet;
}
bool CA2SFix::ProcessLua(bf_read& br,bf_write& bf,uint32 naddr)
{
lua_pushcfunction(L,_aterror);
int iHandler = lua_gettop(L);
lua_getglobal(L,LUA_CALLBACK);
if(lua_isnil(L,-1))
{
lua_pop(L,2);
bf.WriteBitsFromBuffer(&br,br.GetNumBitsLeft());
return true;
}
static char szServer[256] = {0};
static char szMapName[128] = {0};
static char szFolder[128];
static char szGame[64] = {0};
static char szVersion[32] = {0};
int iAppId,iPlayers,iMaxPlayers,iBots;
char szSvType[2] = {0,0};
char szSvEnv[2] = {0,0};
bool bVisibility,bVac;
br.ReadString(szServer,256);
br.ReadString(szMapName,128);
br.ReadString(szFolder,128);
br.ReadString(szGame,64);
iAppId = br.ReadWord();
iPlayers = br.ReadByte();
iMaxPlayers = br.ReadByte();
iBots = br.ReadByte();
szSvType[0] = br.ReadByte();
szSvEnv[0] = br.ReadByte();
bVisibility = br.ReadByte();
bVac = br.ReadByte();
br.ReadString(szVersion,32);
lua_newtable(L);
lua_setstring(L,"name",szServer);
lua_setstring(L,"map",szMapName);
lua_setstring(L,"folder",szFolder);
lua_setstring(L,"game",szGame);
lua_setnumber(L,"appid",iAppId);
lua_setnumber(L,"players",iPlayers);
lua_setnumber(L,"maxplayers",iMaxPlayers);
lua_setnumber(L,"bots",iBots);
lua_setstring(L,"type",szSvType);
lua_setstring(L,"env",szSvEnv);
lua_setnumber(L,"visibility",bVisibility);
lua_setnumber(L,"vac",bVac);
lua_setstring(L,"version",szVersion);
lua_pushstring(L,addr2str(naddr));
lua_pcall(L,2,1,iHandler);
if(lua_isnil(L,-1))
{
lua_pop(L,2);
bf.WriteBitsFromBuffer(&br,br.GetNumBitsLeft());
return true;
}
bf.WriteString(lua_getstring(L,"name"));
bf.WriteString(lua_getstring(L,"map"));
bf.WriteString(lua_getstring(L,"folder"));
bf.WriteString(lua_getstring(L,"game"));
bf.WriteWord(lua_getnumber(L,"appid"));
bf.WriteByte(lua_getnumber(L,"players"));
bf.WriteByte(lua_getnumber(L,"maxplayers"));
bf.WriteByte(lua_getnumber(L,"bots"));
bf.WriteByte(lua_getstring(L,"type")[0]);
bf.WriteByte(lua_getstring(L,"env")[0]);
bf.WriteByte(lua_getnumber(L,"visibility"));
bf.WriteByte(lua_getnumber(L,"vac"));
bf.WriteString(lua_getstring(L,"version"));
bf.WriteBitsFromBuffer(&br,br.GetNumBitsLeft());
lua_pop(L,2);
return true;
}