use protocol buffers to do something cool

This commit is contained in:
2022-09-02 17:39:26 +02:00
parent 210da7c6a5
commit d8919ba684
25 changed files with 1219 additions and 24 deletions

View File

@@ -0,0 +1,62 @@
#include <std_include.hpp>
#include "crypto_key.hpp"
#include "console.hpp"
#include <utils/io.hpp>
namespace crypto_key {
namespace {
bool load_key(utils::cryptography::ecc::key& key) {
std::string data{};
if (!utils::io::read_file("./private.key", &data)) {
return false;
}
key.deserialize(data);
if (!key.is_valid()) {
console::info("Loaded key is invalid!");
return false;
}
return true;
}
utils::cryptography::ecc::key generate_key() {
auto key = utils::cryptography::ecc::generate_key(512);
if (!key.is_valid()) {
throw std::runtime_error("Failed to generate server key!");
}
if (!utils::io::write_file("./private.key", key.serialize())) {
throw std::runtime_error("Failed to write server key!");
}
console::info("Generated cryptographic key: {}", key.get_hash());
return key;
}
utils::cryptography::ecc::key load_or_generate_key() {
utils::cryptography::ecc::key key{};
if (load_key(key)) {
console::info("Loaded cryptographic key: {}", key.get_hash());
return key;
}
return generate_key();
}
utils::cryptography::ecc::key get_key_internal() {
auto key = load_or_generate_key();
if (!utils::io::write_file("./public.key", key.get_public_key())) {
console::info("Failed to write public key!");
}
return key;
}
} // namespace
const utils::cryptography::ecc::key& get() {
static auto key = get_key_internal();
return key;
}
} // namespace crypto_key

View File

@@ -0,0 +1,7 @@
#pragma once
#include "utils/cryptography.hpp"
namespace crypto_key {
const utils::cryptography::ecc::key& get();
}

View File

@@ -1,8 +0,0 @@
#pragma once
namespace network {
using callback =
std::function<void(const game::netadr_s&, const std::string_view&)>;
void on_packet(const std::string& command, const callback& callback);
} // namespace network

View File

@@ -1,15 +1,17 @@
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include "../../loader/component_loader.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
#include "../console.hpp"
#include "network.hpp"
namespace network {
namespace {
std::unordered_map<std::string, network::callback>& get_callbacks() {
static std::unordered_map<std::string, network::callback> network_callbacks{};
std::unordered_map<std::string, callback>& get_callbacks() {
static std::unordered_map<std::string, callback> network_callbacks{};
return network_callbacks;
}
@@ -32,7 +34,6 @@ bool handle_command(game::netadr_s* address, const char* command,
handler->second(*address, data);
return true;
}
} // namespace
int packet_interception_handler(game::netadr_s* from, const char* command,
game::msg_t* message) {
@@ -42,12 +43,61 @@ int packet_interception_handler(game::netadr_s* from, const char* command,
return TRUE;
}
} // namespace
void send(const game::netadr_s& address, const std::string& command,
const std::string& data, const char separator) {
std::string packet = "\xFF\xFF\xFF\xFF";
packet.append(command);
packet.push_back(separator);
packet.append(data);
send_data(address, packet);
}
void send_data(const game::netadr_s& address, const std::string& data) {
auto size = static_cast<int>(data.size());
if (address.type == game::NA_LOOPBACK) {
// TODO: Fix this for loopback
if (size > 1280) {
console::info("Packet was too long. Truncated!\n");
size = 1280;
}
game::NET_SendLoopPacket(game::NS_CLIENT1, size, data.data(), address);
} else {
game::Sys_SendPacket(size, data.data(), address);
}
}
void on_packet(const std::string& command, const callback& callback) {
get_callbacks()[utils::string::to_lower(command)] = callback;
}
class component final : public component_interface {
const char* net_adr_to_string(const game::netadr_s& a) {
if (a.type == game::netadrtype_t::NA_LOOPBACK) {
return "loopback";
}
if (a.type == game::netadrtype_t::NA_BOT) {
return "bot";
}
if (a.type == game::netadrtype_t::NA_IP ||
a.type == game::netadrtype_t::NA_BROADCAST) {
if (a.port) {
return utils::string::va("%u.%u.%u.%u:%u", a.ip[0], a.ip[1], a.ip[2],
a.ip[3], htons(a.port));
}
return utils::string::va("%u.%u.%u.%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
}
return "bad";
}
class network final : public component_interface {
public:
void post_unpack() override {
add_network_commands();
@@ -67,4 +117,4 @@ private:
};
} // namespace network
REGISTER_COMPONENT(network::component)
REGISTER_COMPONENT(network::network)

View File

@@ -0,0 +1,13 @@
#pragma once
namespace network {
void send(const game::netadr_s& address, const std::string& command,
const std::string& data = {}, char separator = ' ');
void send_data(const game::netadr_s& address, const std::string& data);
using callback =
std::function<void(const game::netadr_s&, const std::string_view&)>;
void on_packet(const std::string& command, const callback& callback);
const char* net_adr_to_string(const game::netadr_s& a);
} // namespace network

View File

@@ -0,0 +1,54 @@
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <utils/cryptography.hpp>
#include "network/network.hpp"
#include "crypto_key.hpp"
#include "key_catcher.hpp"
#include <proto/rcon.pb.h>
namespace rcon {
namespace {
utils::cryptography::ecc::key key;
std::string commands;
} // namespace
class component final : public component_interface {
public:
void post_unpack() override {
key = crypto_key::get();
add_key_hooks();
add_commands();
}
private:
static void add_key_hooks() {
// Why commands don't work? I don't know!
key_catcher::on_key_press(
"7", []([[maybe_unused]] const game::LocalClientNum_t& local_client) {
commands = "quit";
network::send(game::localClientConnection->serverAddress,
"rcon_request");
});
}
static void add_commands() {
network::on_packet("rcon_authorization", [](const game::netadr_s& adr,
const std::string_view& data) {
const auto signed_msg =
utils::cryptography::ecc::sign_message(key, std::string(data));
proto::rcon::command info;
info.set_commands(commands);
info.set_signature(signed_msg);
network::send(adr, "rcon_execute", info.SerializeAsString());
});
}
};
} // namespace rcon
REGISTER_COMPONENT(rcon::component)

View File

@@ -69,7 +69,7 @@ struct netadr_s {
unsigned int addrHandleIndex;
};
static_assert(sizeof(netadr_s) == 24);
static_assert(sizeof(netadr_s) == 0x18);
typedef enum {
ERR_FATAL = 0x0,

View File

@@ -54,7 +54,9 @@ WEAK symbol<bool(netsrc_t, netadr_s dest, unsigned char* data, int size)>
WEAK symbol<void(netadr_s*, sockaddr*)> NetadrToSockadr{0x48B460};
WEAK symbol<int(const char* serverName, netadr_s serverRemote)> NET_StringToAdr{
0x4E09A0};
WEAK symbol<SOCKET> query_socket{0x5A861EC};
WEAK symbol<bool(int length, const void* voiddata, netadr_s to)> Sys_SendPacket{0x5145C0};
WEAK symbol<void(netsrc_t sock, int length, const void* data, netadr_s to)> NET_SendLoopPacket{0x4B9DF0};
WEAK symbol<void()> Com_Quit_f{0x556060};
WEAK symbol<void(const msg_t*, unsigned char*, int)> MSG_Init{0x40E030};
@@ -74,11 +76,6 @@ WEAK symbol<int(unsigned __int64, const void*, unsigned int)>
WEAK symbol<XAssetHeader(int type, const char* name, int allowCreateDefault)>
DB_FindXAssetHeader{0x4B25C0};
WEAK symbol<void(const char* text, int maxChars, Font_s* font, float x, float y,
float xScale, float yScale, float rotation, const float* color,
int style)>
R_AddCmdDrawText{0x42C970};
// Variables
WEAK symbol<CmdArgs> cmd_args{0x1C96850};
WEAK symbol<PlayerKeyState> playerKeys{0xB3A38C};

View File

@@ -0,0 +1,8 @@
syntax = "proto3";
package proto.rcon;
message command {
bytes commands = 1;
bytes signature = 2;
}

View File

@@ -1 +1,11 @@
#include "std_include.hpp"
extern "C" {
int s_read_arc4random(void*, std::size_t) { return -1; }
int s_read_getrandom(void*, std::size_t) { return -1; }
int s_read_urandom(void*, std::size_t) { return -1; }
int s_read_ltm_rng(void*, std::size_t) { return -1; }
}

View File

@@ -4,8 +4,10 @@
#define WIN32_LEAN_AND_MEAN
#include <WinSock2.h>
#include <Windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <corecrt_io.h>
#include <fcntl.h>
@@ -15,10 +17,12 @@
#include <iostream>
#include <mutex>
#include <string>
#include <string_view>
#include <source_location>
#include <queue>
#pragma comment(lib, "ntdll.lib")
#pragma comment(lib, "ws2_32.lib")
using namespace std::literals;