From da5547c425f0980ef0388a38fe81414c2eebd284 Mon Sep 17 00:00:00 2001 From: RD42 <42702181+dashr9230@users.noreply.github.com> Date: Thu, 19 Oct 2023 01:24:41 +0200 Subject: [PATCH] Complete and match rcon --- rcon/main.cpp | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++ rcon/main.h | 11 +++ rcon/rcon.dsp | 20 +++-- rcon/rcon.ncb | Bin 33792 -> 41984 bytes rcon/rcon.opt | Bin 48640 -> 48640 bytes 5 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 rcon/main.cpp create mode 100644 rcon/main.h diff --git a/rcon/main.cpp b/rcon/main.cpp new file mode 100644 index 0000000..e64504f --- /dev/null +++ b/rcon/main.cpp @@ -0,0 +1,202 @@ +#include "main.h" + +//-------------------------------------------------- + +bool bQuitApp = false; +HANDLE hConsoleExecuteEvent; +SOCKET s = INVALID_SOCKET; +char* szHost = NULL; +WORD wPort = 0; +char* szPassword= NULL; +sockaddr_in to; +BYTE ipblock[4] = { 0 }; + +//-------------------------------------------------- + +void logprintf(char* format, ...) +{ + va_list ap; + va_start(ap, format); + char buffer[512]; + vsprintf(buffer, format, ap); + va_end(ap); + puts(buffer); +} + +//-------------------------------------------------- + +BOOL WINAPI CtrlHandler(DWORD dwType) +{ + switch (dwType) + { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + bQuitApp = true; + return TRUE; + } + return FALSE; +} + +//-------------------------------------------------- + +DWORD WINAPI NetworkPumpThread(void* pParam) +{ + int to_size = sizeof(to); + char buf[1024]; + int len; + while (true) + { + Sleep(100); + + len = recvfrom(s, buf, sizeof(buf), 0, (sockaddr*)&to, &to_size); + if (len > 13) + { + char* buf_ptr = &buf[11]; + WORD wStrLen = *(WORD*)buf_ptr; + buf_ptr += sizeof(WORD); + char* szMsg = (char*)malloc(wStrLen + 1); + memcpy(szMsg, buf_ptr, wStrLen); + szMsg[wStrLen] = 0; + logprintf("%s", szMsg); + free(szMsg); + } + } + return 0; +} + +//-------------------------------------------------- + +void SendCommand(char* szCommand); + +//-------------------------------------------------- + +DWORD WINAPI ConsoleInputThread(void* pParam) +{ + while (true) + { + Sleep(100); + + char buf[512]; + DWORD dwRead; + ReadConsole(GetStdHandle(STD_INPUT_HANDLE), buf, 512, &dwRead, NULL); + if (dwRead > 2) + { + buf[dwRead-2] = 0; + SendCommand(buf); + } + } + return 0; +} + +//-------------------------------------------------- + +void SendCommand(char* szCommand) +{ + char* newdata = (char*)malloc(11 + strlen(szCommand) + strlen(szPassword) + (sizeof(WORD) * 2)); + char* keep_ptr = newdata; + *(DWORD*)newdata = 0x504D4153; + newdata += sizeof(DWORD); + *(BYTE*)newdata = ipblock[0]; + newdata += sizeof(BYTE); + *(BYTE*)newdata = ipblock[1]; + newdata += sizeof(BYTE); + *(BYTE*)newdata = ipblock[2]; + newdata += sizeof(BYTE); + *(BYTE*)newdata = ipblock[3]; + newdata += sizeof(BYTE); + *(WORD*)newdata = wPort; + newdata += sizeof(WORD); + *newdata = 'x'; + newdata++; + + WORD wStrLen = (WORD)strlen(szPassword); + *(WORD*)newdata = wStrLen; + newdata += sizeof(WORD); + memcpy(newdata, szPassword, wStrLen); + newdata += wStrLen; + + wStrLen = (WORD)strlen(szCommand); + *(WORD*)newdata = wStrLen; + newdata += sizeof(WORD); + memcpy(newdata, szCommand, wStrLen); + newdata += wStrLen; + + sendto(s, keep_ptr, (int)(newdata - keep_ptr), 0, (sockaddr*)&to, sizeof(to)); + free(keep_ptr); +} + +//-------------------------------------------------- + +int main (int argc, char** argv) +{ + WSADATA wsaData; + WSAStartup(0x0202, &wsaData); + + // Print welcome message. + puts("\n SA:MP Command Line Remote Console Client"); + puts(" ----------------------------------------"); + puts(" (C) Copyright 2005-2006 SA:MP Team, v1.0\n"); + + // If there's not enough command line args, print usage. + if (argc < 3) + { + puts(" Usage:"); + puts(" rcon "); + exit(0); + } + + char* szHost = argv[1]; + + hostent* he = gethostbyname(szHost); + if (he) + { + in_addr in; + memcpy(&in, he->h_addr, he->h_length); + szHost = inet_ntoa(in); + } + + int ip = inet_addr(szHost); + if (ip == -1) + { + logprintf("ERROR: Bad host."); + return 0; + } + + sscanf(szHost, "%d.%d.%d.%d", &ipblock[0], &ipblock[1], &ipblock[2], &ipblock[3]); + wPort = (WORD)atoi(argv[2]); + szPassword = argv[3]; + logprintf("Remote Console: %d.%d.%d.%d:%d...\n", ipblock[0], ipblock[1], ipblock[2], ipblock[3], wPort); + + to.sin_family = AF_INET; + to.sin_port = htons(wPort); + to.sin_addr.s_addr = inet_addr(szHost); + + s = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + sockaddr_in s_in; + s_in.sin_addr.S_un.S_addr = INADDR_ANY; + s_in.sin_family = AF_INET; + s_in.sin_port = 0; + bind(s, (sockaddr*)&s_in, sizeof(s_in)); + + // Setup the console + SetConsoleCtrlHandler(CtrlHandler, TRUE); + DWORD dwThreadId; + HANDLE hConsoleThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ConsoleInputThread, NULL, 0, &dwThreadId); + HANDLE hNetworkThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)NetworkPumpThread, NULL, 0, &dwThreadId); + + SendCommand("echo RCON admin connected to server."); + + // While not wanting to quit... + while (!bQuitApp) + { + Sleep(100); + } + + return 0; +} + +//-------------------------------------------------- +// EOF \ No newline at end of file diff --git a/rcon/main.h b/rcon/main.h new file mode 100644 index 0000000..7485112 --- /dev/null +++ b/rcon/main.h @@ -0,0 +1,11 @@ +#pragma once + +#pragma comment(lib, "wsock32.lib") + +#include +#include +#include + +extern bool bQuitApp; + +void logprintf(char* format, ...); \ No newline at end of file diff --git a/rcon/rcon.dsp b/rcon/rcon.dsp index 3ae31cd..db513c7 100644 --- a/rcon/rcon.dsp +++ b/rcon/rcon.dsp @@ -48,8 +48,8 @@ BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "rcon - Win32 Debug" @@ -63,16 +63,16 @@ LINK32=link.exe # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ENDIF @@ -83,10 +83,18 @@ LINK32=link.exe # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\main.cpp +# End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\main.h +# End Source File # End Group # Begin Group "Resource Files" diff --git a/rcon/rcon.ncb b/rcon/rcon.ncb index b1a02a842b6c69430682753aec4381193aac2414..1dadd45a67c6e5985776dfbbd0f4d1d81c88d8a3 100644 GIT binary patch literal 41984 zcmeI4L2nyH6o8)%G^HdaB{VIilx>5AN+Gt|s*s*4Qb2+RRjmXF`LeOs=_0Q;+TDbT z6Bi^-s3*=yTzbd>!3j=1B5}!$YyLqa(L=={<-J{R>p)vss&UuyH`4Rlncbav`+47t z<(YX)ej^Iwu$4HA)y0!1oz*B@iQK?xx{15&#-4L(zE+#sclg5(MC56alAMrl^>C{) zSw60s1OW()GJ!pJ{<=$o00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009UhTk!r^cyjWFZxth4qikJAER+#03u({Uu?&sqqjC!)Z z--(l^*V=V=HEM(%=Pl<`zjOMObJ=Tq8dRjW`rQ{?@RrwBveWBc6#HT4esfv#)x~r5 z*bP=2>v8S$+n3MenR?**ow~J_9?f6vwYlG$8mp_aPf5I}qA;X+?m7Jw`9ozYJxYV1 z$XPw!t8!3fk4j6$?t5KjLggD3yVH)JQTbkFQsq6BXH`fLCZVYDcw(3zC{@RdT+oFR6Y__RE|c zl~?6uapZ`+BFCiLK|I9&t!1-R8W8M>*K%L9GHWsSvD`OvU(9_p_er~+1cC7; za3X#DP(syZ`9gkCZC-X={n}1hKk$YYSU+H1X#IeBne_wa|GoWym0Lex+WG<0)(;$! z7v!+a>S(!N4(Zr>Kwh#dNf3a*6DE*4dFt^`*bthB00f3k0RJC4avFp{VF=i7{n^4; zgCP)rz%U8e`2Y7X8|io!CY-XPenBlfWV^& z*sL`P0uUHa0<8b(T{Oh{pYim9@qOxS{(qr6|G#i={=Zo3|5*PszHcZ`{(ln4=l?bj zY?OAip>5S^d$XCIR&DElwksPY^TKOqH%hjyXG`VUv#68QK2|KER}O8*kHeZTfZw(ob)`~Ph>@Lakdc;?=I;79NO zPs5QA|6?>?F{~~yft_1Bx9qq7$M*5SSUtN6v-lhug6C2cu0(F&yzjTYxW42!qA(6y ziSvmcueojKO0w4U!}?+v1R9WM>BI;G z&a3G!rcj^3hin~D7CC75SD*jeYEc#};)1Qdu-zB7)4}4BkRUKz0yh3%Q`xFamM#9z z-e0rvzc>DejsLyzKP>*wgW`YK`T&dnVY)Z|hZTSQXC?hTapQKSJR`^d6aUAqAwd8F d5P$##AOHafKmY;|fB*y_009U<00M(0@DJsB(oFyW delta 227 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 literal 48640 zcmeHQU2Gjk6`pIa?Hku|(!|8H4ap`gO&Um=UsBT4UdK*qho%m88dDOKIL?xWIJWV1 znjisL(uXFfpsEt$1*GyopWp#h0cllXo!QFopG1ny;#m&+p(X6HC5GIjssX%_I zL}BGq7)k8@j}Ukdw%RyvjSvgc1fg@@0?9)bL0TbqK zK^}x`hHQasg=~XthmhXK;O~Sy1o=2*7vy2cZpb5$E(qy4@OvP8Aia=2$X>`k$fJ;c z2<7F@zO=V2q=vWQBbd*a-wP=P{kH>m=f z^Bu#(dxlW(9isQp==3RfW?;rWYbb$A4z$~bC(lifx%R%(<8C2`4y*Uz^yKFrot`{5 z6=*c&JNovIwDr5AC*A3qdhJ7QAzg`nx&Bu6oX5#5Av}k+H>n#{j=EF0x$aeiJ9ZFo zzv{BY;T{Y9L!&q(zUyZvZtcXJ8X4EWR9zvkOFX3PTE52;KRjZI*U-CvLtGWsWhwv$ zQ-^PKDueD0>0D6hLFzxzk2}hUioMaMm0foowZvN|E%Am}A$}s>q!#1F^r;&#xw%qF zKNTjGo?&uXR*<=U0#R~oTBJFV(& zPIQ0A4z9!i{c{(TU7KLjG01IlRXWP9aoBV_ zIc3-R+tjX0x2auUgI<mF`1y-4Sb~9xDEqXV+1c&8qYG8`$)-6-}bE`HXn3>8&^ zelWU~cML7*$2nNBROAj8Ultc6lc8lUY|vXD9LMNCT7>)W7V)C2Z%ZyuU4Mmpo>IJc zavK4y++4Q`&Brf_Z{8>0&ric9vTM7nMqq%t(osByZ$uSB2L|C z5zok7@;U-F3n?qeE^~J7pX23}dIPh{u9slb)xR|c=keWo%eyuE&6T>9UDw`g5o^$@ z*2IPWpUeE8hEl4a zYG2I%X>gSvAGI_;$oyXgB$0&Z`y}&!5pYsOnEy)wlCGloEav}oRN`SrB{2V|kXRU> z`M+$qGXIwaFXsPJp_RwjjRTMEr=hLP|6$yrKa!96Kj#0!%ZK^D5Q}+)nE$H<9`k>3 zguHly9(VKz^M62t$Nxo}#I21n|7XCH`9A|FsgjugO9fM+67zqF(3mrr|1;wfO?6b1 z`9Fok!uZVpWy6*Ezbtq$|Cb6a)BNiZ%t)TVykwdeUCXV-{9~HUp#~?{(x?12v9k_3vO4y(_3zN??-k>i zZ&<+JVW92;aT{~PGU1=OemP1yIDVSBC+B`I>Kz{~6b_$u&o}MfJ2=#(Z`RWJ+iLw-#K?|HcvW;t6`((Id?N0uAPWqfO%0 z#+d&#;K}^20hClp%>Sl>DN%{}-$ZE48O;BhafzlnD$4w?LSkWj=6|!{%KUE@yqNz@ zh1T)6{eho`^%e8P(D`dU=KTc~!Q2`2IwX_F>px=2SFFT&+=tzB$mjJReKab!0qMx= zKl1vIm5syil1%Afd5~N*XVsa?>pvQS3t#N}CF)L~#p^#B;Yv;{&r9d^ACp1Sa(Mkm zfWhlO;)iwF*=sE$5}b|1YDBzpKCk~+h9YHv*MCe2lu}bX8?XPU5UK7fymeDZ{x6ih`h|5xpc(#-!+8)5#BzyD0_psHj3 zuPQvqWd1LXkQYzTlWnAKtZ#mwsu?x#wE z^#}W~>f;#dKa1KY#0=I!%;q}ksQ-{wf417p+F93sG?!9;>U`>N#rJ=Fr&h0|ug^A* zjLwWbwM7NCs=ziC*siRl$A6yx?X$oDhv$E*hEc;0#v<|jZ=U~cYAMOAf&=xUX_vaw zc>cE$y6_bAgIksVQjh0<8{tY$ERRd&`QOPPX*oRq8({GKZ#>vjx0C2*6LSn1UOA2D zf0v<18Q}TfDS=XIif85d-wKiHzQT*=fAjorp8uVAtuX(a2#q0w`CkJll}XL=v)?Zx zgZaN<{{Ht4Y7WcySc1R*9bPN^{g)7nd4zcUXD#q}{AU~?FP@;s9X$fFK#kAi`QI8a z8c4x!EZ@a d;2f37<3AM=3*+