diff --git a/nethandler.c b/nethandler.c index aa41b9f..ccac8cb 100644 --- a/nethandler.c +++ b/nethandler.c @@ -3,6 +3,7 @@ #include "common.h" #include "rakpeer.h" +#include "processnetworkpacket.h" #include "uncompress.h" #include #include @@ -20,6 +21,7 @@ void simple_redir_call(void *address, void *newtarget) void nethandler_init() { simple_redir_call(UNCOMPRESS_TARGET, uncompress_main); + simple_redir_call(RP_PARSE_NETWORK_PACKET, ProcessNetworkPacket); simple_redir_call(RP_PARSE_CONNECTION_REQ, RakPeer__ParseConnectionRequestPacket); } diff --git a/packet.c b/packet.c new file mode 100644 index 0000000..b56d927 --- /dev/null +++ b/packet.c @@ -0,0 +1,15 @@ + +/* vim: set filetype=c ts=8 noexpandtab: */ + +#include "common.h" +#include "rakpeer.h" +#include "packet.h" + +__declspec(naked) +struct CPacket* __cdecl Packet__AllocPacket(int bitSize) +{ + _asm { + mov eax, 0x44FDE0 + jmp eax + } +} diff --git a/packet.h b/packet.h new file mode 100644 index 0000000..156eac0 --- /dev/null +++ b/packet.h @@ -0,0 +1,15 @@ + +/* vim: set filetype=c ts=8 noexpandtab: */ + +#pragma pack(push,1) +struct CPacket { + short playerIndex; + struct PlayerID playerId; + char _pad[2]; + int bitSize; + char *ptrData; + char deleteData; +}; +#pragma pack(pop) + +struct CPacket* __cdecl Packet__AllocPacket(int bitSize); diff --git a/processnetworkpacket.c b/processnetworkpacket.c new file mode 100644 index 0000000..0da30f4 --- /dev/null +++ b/processnetworkpacket.c @@ -0,0 +1,132 @@ + +/* vim: set filetype=c ts=8 noexpandtab: */ + +#define PROCESSNETWORKPACKET_PRINT + +#ifdef PROCESSNETWORKPACKET_PRINT +#define dprintf(X,...) printf(X,__VA_ARGS__) +#else +#define dprintf(X,...) +#endif + +#include "common.h" +#include "rakpeer.h" +#include "processnetworkpacket.h" +#include "socketlayer.h" +#include "packet.h" +#include "reliability.h" +#include +#include +#include + +static +void ShortResponse(struct CRakPeer *rp, int host, int port, char id) +{ + char buf[2]; + + buf[0] = id; + buf[1] = 0; /*padding cuz 1 byte packet may not get sent*/ + SocketLayer__SendTo(rp->socket, buf, 2, host, port); +} + +static +void HandleConnectedPlayerTryingToConnect( + struct CRakPeer *rp, + struct CRemoteSystem *remoteSystem, + int host, + int port) +{ + if (remoteSystem->connectMode != CONNECTED && + remoteSystem->connectMode != DISCONNECT_ASAP && + remoteSystem->connectMode != DISCONNECT_ASAP_SILENTLY) + { + dprintf("is from connected player, ignore\n"); + return; + } + + dprintf("is from disconnected player, send that it failed\n"); + ShortResponse(rp, host, port, ID_CONNECTION_ATTEMPT_FAILED); +} + +static +void HandleConnectingPlayer( + struct CRakPeer *rp, + struct CRemoteSystem *rs, + int host, + short port, + char *data, + int length) +{ +#define assignRemoteSystem RakPeer__AssignPlayerIDToRemoteSystemList + + struct CPacket *packet; + struct PlayerID playerId; + short playerIndex; + + /*connection cookies, but we don't do that*/ + + if (rs != NULL) { + dprintf("connection request is from already connected playa\n"); + HandleConnectedPlayerTryingToConnect(rp, rs, host, port); + return; + } + + dprintf("it's a new player\n"); + playerId.binaryAddress = host; + playerId.port = port; + + if (!assignRemoteSystem(rp, playerId, UNVERIFIED_SENDER)) { + dprintf("server is full\n"); + ShortResponse(rp, host, port, ID_NO_FREE_INCOMING_CONNECTIONS); + return; + } + + playerIndex = RakPeer__GetIndexFromPlayerID(rp, playerId, 1); + dprintf("assigned index %hd\n", playerIndex); + + packet = Packet__AllocPacket(1); + packet->playerId = playerId; + packet->bitSize = 8; + packet->playerIndex = playerIndex; + packet->ptrData[0] = ID_OPEN_CONNECTION_REQUEST; + RakPeer__AddPacketToProducer(rp, packet); + + ShortResponse(rp, host, port, ID_OPEN_CONNECTION_REPLY); +} + +void __stdcall ProcessNetworkPacket( + int host, + short port, + char *data, + int length, + struct CRakPeer *rp) +{ + struct CRemoteSystem *rs; + struct PlayerID playerId; + int isPacketFlood; + + playerId.binaryAddress = host; + playerId.port = port; + + if (data[0] == ID_OPEN_CONNECTION_REQUEST && length == 3) { + dprintf("got connection request\n"); + rs = RakPeer__GetRemoteSystemFromPlayerID(rp, playerId, 1, 1); + HandleConnectingPlayer(rp, rs, host, port, data, length); + return; + } + + rs = RakPeer__GetRemoteSystemFromPlayerID(rp, playerId, 1, 1); + if (!rs) { + dprintf("incoming from UNCONNECTED, ignoring\n"); + return; + } + + ReliabilityLayer__HandleSocketReceiveFromConnectedPlayer( + (void*) &rs->reliabilityLayer, + data, + length, + playerId, + &rp->messageHandlerList, + rp->MTUSize, + &isPacketFlood); +} diff --git a/processnetworkpacket.h b/processnetworkpacket.h new file mode 100644 index 0000000..e894d01 --- /dev/null +++ b/processnetworkpacket.h @@ -0,0 +1,11 @@ + +/* vim: set filetype=c ts=8 noexpandtab: */ + +#define RP_PARSE_NETWORK_PACKET ((void*) 0x462C21) + +void __stdcall ProcessNetworkPacket( + int binaryAddress, + short port, + char *data, + int length, + struct CRakPeer *rakPeer); diff --git a/rakpeer.c b/rakpeer.c index a1d43d9..7cc21f5 100644 --- a/rakpeer.c +++ b/rakpeer.c @@ -9,10 +9,70 @@ #include #include +__declspec(naked) +int __stdcall RakPeer__GetIndexFromPlayerID( + struct CRakPeer *this, + struct PlayerID playerId, + char calledFromNetworkThread) +{ + _asm { + pop eax + pop ecx + push eax + mov eax, 0x453A40 + jmp eax + } +} + +__declspec(naked) +int __stdcall RakPeer__AddPacketToProducer( + struct CRakPeer *this, + struct CPacket *packet) +{ + _asm { + pop eax + pop ecx + push eax + mov eax, 0x4523D0 + jmp eax + } +} + +__declspec(naked) +int __stdcall RakPeer__AssignPlayerIDToRemoteSystemList( + struct CRakPeer *this, + struct PlayerID playerId, + int connectionMode) +{ + _asm { + pop eax + pop ecx + push eax + mov eax, 0x455E00 + jmp eax + } +} + +__declspec(naked) +struct CRemoteSystem* __stdcall RakPeer__GetRemoteSystemFromPlayerID( + struct CRakPeer *this, + struct PlayerID playerId, + char calledFromNetworkThread, + char onlyActive) +{ + _asm { + pop eax + pop ecx + push eax + mov eax, 0x453AF0 + jmp eax + } +} + static int __declspec(naked) RakPeer__OnConnectionRequest( struct CRakPeer *this, - struct CRakPeer__RemoteSystemStruct *remoteSystem, + struct CRemoteSystem *remoteSystem, char *AESKey, char setAESkey) { @@ -88,7 +148,7 @@ short __declspec(naked) RakPeer__AllowIncomingConnectionsInternal( static void RakPeer__ParseConnectionRequestPacketInternal( struct CRakPeer *this, - struct CRakPeer__RemoteSystemStruct *remoteSystem, + struct CRemoteSystem *remoteSystem, struct PlayerID playerId, char *data, char byteSize) diff --git a/rakpeer.h b/rakpeer.h index f991899..56f3dd7 100644 --- a/rakpeer.h +++ b/rakpeer.h @@ -16,11 +16,12 @@ #define ID_CONNECTION_REQUEST 0x0B #define ID_OPEN_CONNECTION_REQUEST 0x18 #define ID_OPEN_CONNECTION_REPLY 0x19 -#define ID_CONNECTION_ATTEMPT_FAILED 0x1D +#define ID_CONNECTION_ATTEMPT_FAILED 0x1D /*results in server did not respond*/ #define ID_NEW_INCOMING_CONNECTION 0x1E #define ID_NO_FREE_INCOMING_CONNECTIONS 0x1F #define ID_CONNECTION_BANNED 0x24 #define ID_INVALID_PASSWORD 0x25 +#define ID_MODIFIED_PACKET 0x26 #define SYSTEM_PRIORITY 0 #define HIGH_PRIORITY 1 @@ -40,9 +41,9 @@ struct PlayerID { }; EXPECT_SIZE(struct PlayerID, 0x8); -struct CRakPeer__RemoteSystemStruct { +struct CRemoteSystem { char _pad0[0x10-0x0]; - void *reliabilityLayer; + int reliabilityLayer; char _pad14[0x778-0x14]; int lowestPing; int nextPingTime; @@ -70,17 +71,41 @@ struct CRakPeer { unsigned char incomingPasswordLength; char _pad33B[0x33C-0x33B]; struct CRakPeer__RemoteSystemStruct *remoteSystemList; - char _pad340[0x7DC-0x340]; + char _pad340[0x3B8-0x340]; + int messageHandlerList; + char _pad3BC[0x7DC-0x3BC]; void *inputTree; /*HuffmanEncodingTree**/ void *outputTree; /*HuffmanEncodingTree**/ char _pad7E4[0xC0C-0x7E4]; int MTUSize; - char _padC10[0xD95-0xC10]; + char _padC18[0xC18-0xC10]; + void *socket; + char _padC1C[0xD95-0xC1C]; char usingSecurity; /*incomplete*/ }; #pragma pack(pop) +int __stdcall RakPeer__GetIndexFromPlayerID( + struct CRakPeer *this, + struct PlayerID playerId, + char calledFromNetworkThread); + +int __stdcall RakPeer__AddPacketToProducer( + struct CRakPeer *this, + struct CPacket *packet); + +int __stdcall RakPeer__AssignPlayerIDToRemoteSystemList( + struct CRakPeer *this, + struct PlayerID playerId, + int connectionMode); + +struct CRemoteSystem* __stdcall RakPeer__GetRemoteSystemFromPlayerID( + struct CRakPeer *this, + struct PlayerID playerId, + char calledFromNetworkThread, + char onlyActive); + /** int __thiscall RakPeer__ParseConnectionRequestPacket( CRakPeer *this, diff --git a/reliability.c b/reliability.c new file mode 100644 index 0000000..7c4d991 --- /dev/null +++ b/reliability.c @@ -0,0 +1,25 @@ + +/* vim: set filetype=c ts=8 noexpandtab: */ + +#include "common.h" +#include "rakpeer.h" +#include "reliability.h" + +__declspec(naked) +int __stdcall ReliabilityLayer__HandleSocketReceiveFromConnectedPlayer( + struct CReliabilityLayer *this, + char *buffer, + int length, + struct PlayerID playerId, + void *messageHandlerList, + int MTUSize, + int *ptrOutIsPacketFlood) +{ + _asm { + pop eax + pop ecx + push eax + mov eax, 0x45F7E0 + jmp eax + } +} diff --git a/reliability.h b/reliability.h new file mode 100644 index 0000000..bc595b0 --- /dev/null +++ b/reliability.h @@ -0,0 +1,11 @@ + +/* vim: set filetype=c ts=8 noexpandtab: */ + +int __stdcall ReliabilityLayer__HandleSocketReceiveFromConnectedPlayer( + struct CReliabilityLayer *this, + char *buffer, + int length, + struct PlayerID playerId, + void *messageHandlerList, + int MTUSize, + int *ptrOutIsPacketFlood); diff --git a/samp-re.vcproj b/samp-re.vcproj index 3808e7b..96b9ae0 100644 --- a/samp-re.vcproj +++ b/samp-re.vcproj @@ -101,10 +101,26 @@ RelativePath=".\nethandler.c" > + + + + + + + + @@ -113,6 +129,22 @@ RelativePath=".\rakpeer.h" > + + + + + + + + diff --git a/socketlayer.c b/socketlayer.c new file mode 100644 index 0000000..4c20c26 --- /dev/null +++ b/socketlayer.c @@ -0,0 +1,18 @@ + +/* vim: set filetype=c ts=8 noexpandtab: */ + +#include "socketlayer.h" + +__declspec(naked) +int __stdcall SocketLayer__SendTo( + void *socket, + char *buf, + int len, + int host, + short port) +{ + _asm { + mov eax, 0x462C50 + jmp eax + } +} diff --git a/socketlayer.h b/socketlayer.h new file mode 100644 index 0000000..1f3be7c --- /dev/null +++ b/socketlayer.h @@ -0,0 +1,9 @@ + +/* vim: set filetype=c ts=8 noexpandtab: */ + +int __stdcall SocketLayer__SendTo( + void *socket, + char *buf, + int len, + int host, + short port);