OpenFusion/src/CNProtocol.hpp

216 lines
5.5 KiB
C++
Raw Normal View History

#pragma once
2020-08-18 20:42:30 +00:00
2020-08-23 21:09:31 +00:00
#define DEBUGLOG(x) if (settings::VERBOSITY) {x};
2020-08-18 20:42:30 +00:00
#include <iostream>
#include <stdio.h>
#include <stdint.h>
#ifdef _WIN32
2020-08-24 18:23:28 +00:00
// windows
#define NOMINMAX
2020-08-24 18:23:28 +00:00
#define _WINSOCK_DEPRECATED_NO_WARNINGS
2020-08-18 20:42:30 +00:00
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
typedef char buffer_t;
2020-08-24 18:23:28 +00:00
#define OF_ERRNO WSAGetLastError()
#define OF_EWOULD WSAEWOULDBLOCK
2020-08-18 20:42:30 +00:00
#define SOCKETINVALID(x) (x == INVALID_SOCKET)
#define SOCKETERROR(x) (x == SOCKET_ERROR)
#else
// posix platform
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
typedef int SOCKET;
typedef void buffer_t;
2020-08-24 18:23:28 +00:00
#define OF_ERRNO errno
#define OF_EWOULD EWOULDBLOCK
2020-08-18 20:42:30 +00:00
#define SOCKETINVALID(x) (x < 0)
#define SOCKETERROR(x) (x == -1)
#endif
#include <fcntl.h>
#include <string>
#include <cstring>
#include <csignal>
#include <list>
#include <queue>
2020-08-23 21:09:31 +00:00
#include "Defines.hpp"
#include "settings.hpp"
2020-08-19 20:42:44 +00:00
#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS)
2020-08-19 00:52:02 +00:00
#include "mingw/mingw.mutex.h"
#else
2020-08-19 00:52:02 +00:00
#include <mutex>
#endif
2020-08-18 20:42:30 +00:00
/*
Packets format (sent from the client):
2020-08-19 00:11:31 +00:00
[4 bytes] - size of packet including the 4 byte packet type
2020-08-18 20:42:30 +00:00
[size bytes] - Encrypted packet (byte swapped && xor'd with 8 byte key; see CNSocketEncryption)
[4 bytes] - packet type (which is a combination of the first 4 bytes of the packet and a checksum in some versions)
[structure] - one member contains length of trailing data (expressed in packet-dependant structures)
[trailing data] - optional variable-length data that only some packets make use of
2020-08-18 20:42:30 +00:00
*/
// error checking calloc wrapper
inline void* xmalloc(size_t sz) {
void* res = calloc(1, sz);
if (res == NULL) {
std::cerr << "[FATAL] OpenFusion: calloc failed to allocate memory!" << std::endl;
exit(EXIT_FAILURE);
}
return res;
}
// overflow-safe validation of variable-length packets
// for outbound packets
inline bool validOutVarPacket(size_t base, int32_t npayloads, size_t plsize) {
// check for multiplication overflow
if (npayloads > 0 && (CN_PACKET_BUFFER_SIZE - 8) / (size_t)npayloads < plsize)
return false;
// it's safe to multiply
size_t trailing = npayloads * plsize;
// does it fit in a packet?
if (base + trailing > CN_PACKET_BUFFER_SIZE - 8)
return false;
// everything is a-ok!
return true;
}
// for inbound packets
inline bool validInVarPacket(size_t base, int32_t npayloads, size_t plsize, size_t datasize) {
// check for multiplication overflow
if (npayloads > 0 && (CN_PACKET_BUFFER_SIZE - 8) / (size_t)npayloads < plsize)
return false;
// it's safe to multiply
size_t trailing = npayloads * plsize;
// make sure size is exact
// datasize has already been validated against CN_PACKET_BUFFER_SIZE
if (datasize != base + trailing)
return false;
// everything is a-ok!
return true;
}
2020-08-18 20:42:30 +00:00
namespace CNSocketEncryption {
// you won't believe how complicated they made it in the client :facepalm:
static constexpr const char* defaultKey = "m@rQn~W#";
static const unsigned int keyLength = 8;
int Encrypt_byte_change_A(int ERSize, uint8_t* data, int size);
int xorData(uint8_t* buffer, uint8_t* key, int size);
uint64_t createNewKey(uint64_t uTime, int32_t iv1, int32_t iv2);
int encryptData(uint8_t* buffer, uint8_t* key, int size);
int decryptData(uint8_t* buffer, uint8_t* key, int size);
}
2020-08-22 23:31:09 +00:00
struct CNPacketData {
2020-08-18 20:42:30 +00:00
void* buf;
int size;
uint32_t type;
2020-08-22 23:31:09 +00:00
CNPacketData(void* b, uint32_t t, int l);
};
enum ACTIVEKEY {
SOCKETKEY_E,
SOCKETKEY_FE
2020-08-18 20:42:30 +00:00
};
struct Player;
2020-08-18 20:42:30 +00:00
class CNSocket;
typedef void (*PacketHandler)(CNSocket* sock, CNPacketData* data);
class CNSocket {
private:
uint64_t EKey;
uint64_t FEKey;
int32_t readSize = 0;
uint8_t readBuffer[CN_PACKET_BUFFER_SIZE];
2020-08-18 20:42:30 +00:00
int readBufferIndex = 0;
bool activelyReading = false;
bool alive = true;
2020-08-22 23:31:09 +00:00
ACTIVEKEY activeKey;
2020-08-18 20:42:30 +00:00
bool sendData(uint8_t* data, int size);
2020-08-24 18:23:28 +00:00
int recvData(buffer_t* data, int size);
2020-08-18 20:42:30 +00:00
public:
SOCKET sock;
PacketHandler pHandler;
Player *plr = nullptr;
2020-08-18 20:42:30 +00:00
CNSocket(SOCKET s, PacketHandler ph);
void setEKey(uint64_t k);
void setFEKey(uint64_t k);
uint64_t getEKey();
uint64_t getFEKey();
2020-08-22 23:31:09 +00:00
void setActiveKey(ACTIVEKEY t);
2020-08-18 20:42:30 +00:00
void kill();
2020-08-22 23:31:09 +00:00
void sendPacket(void* buf, uint32_t packetType, size_t size);
2020-08-18 20:42:30 +00:00
void step();
bool isAlive();
};
class CNServer;
typedef void (*TimerHandler)(CNServer* serv, time_t time);
// timer struct
struct TimerEvent {
TimerHandler handlr;
time_t delta; // time to be added to the current time on reset
time_t scheduledEvent; // time to call handlr()
TimerEvent(TimerHandler h, time_t d): handlr(h), delta(d) {
scheduledEvent = 0;
}
};
2020-08-18 20:42:30 +00:00
// in charge of accepting new connections and making sure each connection is kept alive
class CNServer {
protected:
std::list<CNSocket*> connections;
2020-08-19 01:34:39 +00:00
std::mutex activeCrit;
2020-08-18 20:42:30 +00:00
SOCKET sock;
uint16_t port;
socklen_t addressSize;
struct sockaddr_in address;
void init();
2020-08-19 00:52:02 +00:00
bool active = true;
2020-08-18 20:42:30 +00:00
public:
PacketHandler pHandler;
CNServer();
CNServer(uint16_t p);
void start();
2020-08-19 00:52:02 +00:00
void kill();
2020-08-23 21:09:31 +00:00
static void printPacket(CNPacketData *data, int type);
2020-08-22 23:31:09 +00:00
virtual void newConnection(CNSocket* cns);
2020-08-18 20:42:30 +00:00
virtual void killConnection(CNSocket* cns);
virtual void onStep();
2020-08-18 20:42:30 +00:00
};