2020-08-23 17:14:54 +00:00
|
|
|
#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>
|
2020-09-14 13:53:48 +00:00
|
|
|
#ifdef _WIN32
|
2020-08-24 18:23:28 +00:00
|
|
|
// windows
|
2020-10-07 17:03:00 +00:00
|
|
|
#ifndef NOMINMAX
|
2020-10-02 18:31:22 +00:00
|
|
|
#define NOMINMAX
|
2020-10-07 17:03:00 +00:00
|
|
|
#endif
|
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-12-04 23:52:36 +00:00
|
|
|
#define PollFD WSAPOLLFD
|
|
|
|
#define poll WSAPoll
|
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>
|
2020-12-04 19:09:39 +00:00
|
|
|
#include <poll.h>
|
2020-08-18 20:42:30 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
typedef int SOCKET;
|
|
|
|
typedef void buffer_t;
|
2020-12-04 23:52:36 +00:00
|
|
|
#define PollFD struct pollfd
|
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-12-05 03:58:49 +00:00
|
|
|
#include <unordered_map>
|
2020-12-05 20:59:37 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
2020-08-18 20:42:30 +00:00
|
|
|
|
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"
|
2020-09-14 13:53:48 +00:00
|
|
|
#else
|
2020-08-19 00:52:02 +00:00
|
|
|
#include <mutex>
|
|
|
|
#endif
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
/*
|
2020-10-19 17:26:14 +00:00
|
|
|
* Packets format (sent from the client):
|
|
|
|
* [4 bytes] - size of packet including the 4 byte packet type
|
|
|
|
* [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) {
|
2020-12-05 03:58:49 +00:00
|
|
|
std::cerr << "[FATAL] OpenFusion: out of memory!" << std::endl;
|
2020-08-18 20:42:30 +00:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-08-28 14:09:26 +00:00
|
|
|
// 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
|
2020-09-08 01:01:47 +00:00
|
|
|
if (npayloads > 0 && (CN_PACKET_BUFFER_SIZE - 8) / (size_t)npayloads < plsize)
|
2020-08-28 14:09:26 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// it's safe to multiply
|
|
|
|
size_t trailing = npayloads * plsize;
|
|
|
|
|
|
|
|
// does it fit in a packet?
|
2020-09-08 01:01:47 +00:00
|
|
|
if (base + trailing > CN_PACKET_BUFFER_SIZE - 8)
|
2020-08-28 14:09:26 +00:00
|
|
|
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
|
2020-09-08 01:01:47 +00:00
|
|
|
if (npayloads > 0 && (CN_PACKET_BUFFER_SIZE - 8) / (size_t)npayloads < plsize)
|
2020-08-28 14:09:26 +00:00
|
|
|
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-12-05 22:16:09 +00:00
|
|
|
bool setSockNonblocking(SOCKET listener, SOCKET newSock);
|
|
|
|
|
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
|
|
|
};
|
|
|
|
|
|
|
|
class CNSocket;
|
|
|
|
typedef void (*PacketHandler)(CNSocket* sock, CNPacketData* data);
|
|
|
|
|
|
|
|
class CNSocket {
|
|
|
|
private:
|
|
|
|
uint64_t EKey;
|
|
|
|
uint64_t FEKey;
|
|
|
|
int32_t readSize = 0;
|
2020-08-28 14:09:26 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
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();
|
|
|
|
};
|
|
|
|
|
2020-08-24 21:11:40 +00:00
|
|
|
class CNServer;
|
2020-09-16 15:45:53 +00:00
|
|
|
typedef void (*TimerHandler)(CNServer* serv, time_t time);
|
2020-08-24 21:11:40 +00:00
|
|
|
|
|
|
|
// timer struct
|
|
|
|
struct TimerEvent {
|
|
|
|
TimerHandler handlr;
|
2020-09-16 15:45:53 +00:00
|
|
|
time_t delta; // time to be added to the current time on reset
|
|
|
|
time_t scheduledEvent; // time to call handlr()
|
2020-08-24 21:11:40 +00:00
|
|
|
|
2020-09-16 15:45:53 +00:00
|
|
|
TimerEvent(TimerHandler h, time_t d): handlr(h), delta(d) {
|
2020-08-24 21:11:40 +00:00
|
|
|
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:
|
2020-12-05 03:58:49 +00:00
|
|
|
std::unordered_map<SOCKET, CNSocket*> connections;
|
2020-08-19 01:34:39 +00:00
|
|
|
std::mutex activeCrit;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
2020-12-05 03:58:49 +00:00
|
|
|
const size_t STARTFDSCOUNT = 8; // number of initial PollFD slots
|
2020-12-05 20:59:37 +00:00
|
|
|
std::vector<PollFD> fds;
|
2020-12-05 03:58:49 +00:00
|
|
|
|
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);
|
|
|
|
|
2020-12-05 03:58:49 +00:00
|
|
|
void addPollFD(SOCKET s);
|
|
|
|
void removePollFD(int i);
|
|
|
|
|
2020-08-18 20:42:30 +00:00
|
|
|
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-12-06 00:44:37 +00:00
|
|
|
virtual bool checkExtraSockets(int i);
|
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);
|
2020-09-17 19:22:31 +00:00
|
|
|
virtual void onStep();
|
2020-08-18 20:42:30 +00:00
|
|
|
};
|