Merge branch 'master' into jgrpp
# Conflicts: # src/console_cmds.cpp # src/network/core/config.h # src/network/core/packet.h # src/network/core/tcp.cpp # src/network/core/tcp_game.cpp # src/network/core/tcp_game.h # src/network/network_client.cpp # src/network/network_client.h # src/network/network_gui.h # src/network/network_server.cpp # src/network/network_server.h # src/table/settings/network_secrets_settings.ini
This commit is contained in:
@@ -935,6 +935,7 @@ DEF_CONSOLE_CMD(ConRcon)
|
|||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
IConsolePrint(CC_HELP, "Remote control the server from another client. Usage: 'rcon <password> <command>'.");
|
IConsolePrint(CC_HELP, "Remote control the server from another client. Usage: 'rcon <password> <command>'.");
|
||||||
IConsolePrint(CC_HELP, "Remember to enclose the command in quotes, otherwise only the first parameter is sent.");
|
IConsolePrint(CC_HELP, "Remember to enclose the command in quotes, otherwise only the first parameter is sent.");
|
||||||
|
IConsolePrint(CC_HELP, "When your client's public key is in the 'authorized keys' for 'rcon', '*' may be used instead of the password.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2139,6 +2140,100 @@ DEF_CONSOLE_CMD(ConCompanyPassword)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** All the known authorized keys with their name. */
|
||||||
|
static std::vector<std::pair<std::string_view, std::vector<std::string> *>> _console_cmd_authorized_keys{
|
||||||
|
{ "rcon", &_settings_client.network.rcon_authorized_keys },
|
||||||
|
{ "server", &_settings_client.network.server_authorized_keys },
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple helper to find the location of the given authorized key in the authorized keys.
|
||||||
|
* @param authorized_keys The keys to look through.
|
||||||
|
* @param authorized_key The key to look for.
|
||||||
|
* @return The iterator to the location of the authorized key, or \c authorized_keys.end().
|
||||||
|
*/
|
||||||
|
static auto FindKey(std::vector<std::string> *authorized_keys, std::string_view authorized_key)
|
||||||
|
{
|
||||||
|
return std::find_if(authorized_keys->begin(), authorized_keys->end(), [authorized_key](auto &value) { return StrEqualsIgnoreCase(value, authorized_key); });
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_CONSOLE_CMD(ConNetworkAuthorizedKey)
|
||||||
|
{
|
||||||
|
if (argc <= 2) {
|
||||||
|
IConsolePrint(CC_HELP, "List and update authorized keys. Usage: 'authorized_key list [type]|add [type] [key]|remove [type] [key]'.");
|
||||||
|
IConsolePrint(CC_HELP, " list: list all the authorized keys of the given type.");
|
||||||
|
IConsolePrint(CC_HELP, " add: add the given key to the authorized keys of the given type.");
|
||||||
|
IConsolePrint(CC_HELP, " remove: remove the given key from the authorized keys of the given type; use 'all' to remove all authorized keys.");
|
||||||
|
IConsolePrint(CC_HELP, "Instead of a key, use 'client:<id>' to add/remove the key of that given client.");
|
||||||
|
|
||||||
|
std::string buffer;
|
||||||
|
for (auto [name, _] : _console_cmd_authorized_keys) fmt::format_to(std::back_inserter(buffer), ", {}", name);
|
||||||
|
IConsolePrint(CC_HELP, "The supported types are: all{}.", buffer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid_type = false; ///< Whether a valid type was given.
|
||||||
|
|
||||||
|
for (auto [name, authorized_keys] : _console_cmd_authorized_keys) {
|
||||||
|
if (!StrEqualsIgnoreCase(argv[2], name) && !StrEqualsIgnoreCase(argv[2], "all")) continue;
|
||||||
|
|
||||||
|
valid_type = true;
|
||||||
|
|
||||||
|
if (StrEqualsIgnoreCase(argv[1], "list")) {
|
||||||
|
IConsolePrint(CC_WHITE, "The authorized keys for {} are:", name);
|
||||||
|
for (auto &authorized_key : *authorized_keys) IConsolePrint(CC_INFO, " {}", authorized_key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc <= 3) {
|
||||||
|
IConsolePrint(CC_ERROR, "You must enter the key.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string authorized_key = argv[3];
|
||||||
|
if (StrStartsWithIgnoreCase(authorized_key, "client:")) {
|
||||||
|
std::string id_string(authorized_key.substr(7));
|
||||||
|
authorized_key = NetworkGetPublicKeyOfClient(static_cast<ClientID>(std::stoi(id_string)));
|
||||||
|
if (authorized_key.empty()) {
|
||||||
|
IConsolePrint(CC_ERROR, "You must enter a valid client id; see 'clients'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto iter = FindKey(authorized_keys, authorized_key);
|
||||||
|
|
||||||
|
if (StrEqualsIgnoreCase(argv[1], "add")) {
|
||||||
|
if (iter == authorized_keys->end()) {
|
||||||
|
authorized_keys->push_back(authorized_key);
|
||||||
|
IConsolePrint(CC_INFO, "Added {} to {}.", authorized_key, name);
|
||||||
|
} else {
|
||||||
|
IConsolePrint(CC_WARNING, "Not added {} to {} as it already exists.", authorized_key, name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StrEqualsIgnoreCase(argv[1], "remove")) {
|
||||||
|
if (iter != authorized_keys->end()) {
|
||||||
|
authorized_keys->erase(iter);
|
||||||
|
IConsolePrint(CC_INFO, "Removed {} from {}.", authorized_key, name);
|
||||||
|
} else {
|
||||||
|
IConsolePrint(CC_WARNING, "Not removed {} from {} as it does not exist.", authorized_key, name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IConsolePrint(CC_WARNING, "No valid action was given.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid_type) {
|
||||||
|
IConsolePrint(CC_WARNING, "No valid type was given.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DEF_CONSOLE_CMD(ConCompanyPasswordHash)
|
DEF_CONSOLE_CMD(ConCompanyPasswordHash)
|
||||||
{
|
{
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
@@ -4052,6 +4147,9 @@ void IConsoleStdLibRegister()
|
|||||||
IConsole::CmdRegister("unpause", ConUnpauseGame, ConHookServerOrNoNetwork);
|
IConsole::CmdRegister("unpause", ConUnpauseGame, ConHookServerOrNoNetwork);
|
||||||
IConsole::CmdRegister("step", ConStepGame, ConHookNoNetwork);
|
IConsole::CmdRegister("step", ConStepGame, ConHookNoNetwork);
|
||||||
|
|
||||||
|
IConsole::CmdRegister("authorized_key", ConNetworkAuthorizedKey, ConHookServerOnly);
|
||||||
|
IConsole::AliasRegister("ak", "authorized_key %+");
|
||||||
|
|
||||||
IConsole::CmdRegister("company_pw", ConCompanyPassword, ConHookNeedNetwork);
|
IConsole::CmdRegister("company_pw", ConCompanyPassword, ConHookNeedNetwork);
|
||||||
IConsole::AliasRegister("company_password", "company_pw %+");
|
IConsole::AliasRegister("company_password", "company_pw %+");
|
||||||
IConsole::CmdRegister("company_pw_hash", ConCompanyPasswordHash, ConHookServerOnly);
|
IConsole::CmdRegister("company_pw_hash", ConCompanyPasswordHash, ConHookServerOnly);
|
||||||
|
@@ -2574,6 +2574,7 @@ STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Your pla
|
|||||||
STR_NETWORK_ERROR_BAD_SERVER_NAME :{WHITE}Your server name has not been set. The name can be set at the top of the Multiplayer window
|
STR_NETWORK_ERROR_BAD_SERVER_NAME :{WHITE}Your server name has not been set. The name can be set at the top of the Multiplayer window
|
||||||
STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}The revision of this client does not match the server's revision
|
STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}The revision of this client does not match the server's revision
|
||||||
STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Wrong password
|
STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Wrong password
|
||||||
|
STR_NETWORK_ERROR_NOT_ON_ALLOW_LIST :{WHITE}You are not on the list of allowed clients
|
||||||
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The server is full
|
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The server is full
|
||||||
STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}You are banned from this server
|
STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}You are banned from this server
|
||||||
STR_NETWORK_ERROR_KICKED :{WHITE}You were kicked out of the game
|
STR_NETWORK_ERROR_KICKED :{WHITE}You were kicked out of the game
|
||||||
@@ -2589,7 +2590,7 @@ STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Your pla
|
|||||||
STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible connection loss
|
STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible connection loss
|
||||||
STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}The last {NUM} second{P "" s} no data has arrived from the server
|
STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}The last {NUM} second{P "" s} no data has arrived from the server
|
||||||
|
|
||||||
###length 21
|
###length 22
|
||||||
STR_NETWORK_ERROR_CLIENT_GENERAL :general error
|
STR_NETWORK_ERROR_CLIENT_GENERAL :general error
|
||||||
STR_NETWORK_ERROR_CLIENT_DESYNC :desync error
|
STR_NETWORK_ERROR_CLIENT_DESYNC :desync error
|
||||||
STR_NETWORK_ERROR_CLIENT_SAVEGAME :could not load map
|
STR_NETWORK_ERROR_CLIENT_SAVEGAME :could not load map
|
||||||
@@ -2601,6 +2602,7 @@ STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :received invali
|
|||||||
STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :wrong revision
|
STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :wrong revision
|
||||||
STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :name already in use
|
STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :name already in use
|
||||||
STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :wrong password
|
STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :wrong password
|
||||||
|
STR_NETWORK_ERROR_CLIENT_NOT_ON_ALLOW_LIST :not on allow list
|
||||||
STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :wrong company in DoCommand
|
STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :wrong company in DoCommand
|
||||||
STR_NETWORK_ERROR_CLIENT_KICKED :kicked by server
|
STR_NETWORK_ERROR_CLIENT_KICKED :kicked by server
|
||||||
STR_NETWORK_ERROR_CLIENT_CHEATER :was trying to use a cheat
|
STR_NETWORK_ERROR_CLIENT_CHEATER :was trying to use a cheat
|
||||||
|
@@ -16,6 +16,9 @@ add_files(
|
|||||||
network_content_gui.h
|
network_content_gui.h
|
||||||
network_coordinator.cpp
|
network_coordinator.cpp
|
||||||
network_coordinator.h
|
network_coordinator.h
|
||||||
|
network_crypto.cpp
|
||||||
|
network_crypto.h
|
||||||
|
network_crypto_internal.h
|
||||||
network_func.h
|
network_func.h
|
||||||
network_gamelist.cpp
|
network_gamelist.cpp
|
||||||
network_gamelist.h
|
network_gamelist.h
|
||||||
|
@@ -93,6 +93,12 @@ static const uint NETWORK_GRF_NAME_LENGTH = 80; ///< Maxim
|
|||||||
*/
|
*/
|
||||||
static const uint NETWORK_MAX_GRF_COUNT = 255;
|
static const uint NETWORK_MAX_GRF_COUNT = 255;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum length of the hexadecimal encoded secret keys, in bytes including '\0'.
|
||||||
|
* This is related to \c X25519_KEY_SIZE in the network crypto internals.
|
||||||
|
*/
|
||||||
|
static const uint NETWORK_SECRET_KEY_LENGTH = 32 * 2 + 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum version supported in PACKET_SERVER_GAME_INFO_EXTENDED
|
* Maximum version supported in PACKET_SERVER_GAME_INFO_EXTENDED
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#define NETWORK_CORE_CORE_H
|
#define NETWORK_CORE_CORE_H
|
||||||
|
|
||||||
#include "../../newgrf_config.h"
|
#include "../../newgrf_config.h"
|
||||||
|
#include "../network_crypto.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
bool NetworkCoreInitialize();
|
bool NetworkCoreInitialize();
|
||||||
@@ -43,6 +44,11 @@ class NetworkSocketHandler {
|
|||||||
private:
|
private:
|
||||||
bool has_quit; ///< Whether the current client has quit/send a bad packet
|
bool has_quit; ///< Whether the current client has quit/send a bad packet
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend struct Packet;
|
||||||
|
std::unique_ptr<class NetworkEncryptionHandler> receive_encryption_handler; ///< The handler for decrypting received packets.
|
||||||
|
std::unique_ptr<class NetworkEncryptionHandler> send_encryption_handler; ///< The handler for encrypting sent packets.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Create a new unbound socket */
|
/** Create a new unbound socket */
|
||||||
NetworkSocketHandler() { this->has_quit = false; }
|
NetworkSocketHandler() { this->has_quit = false; }
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
* loose some the data of the packet, so there you pass the maximum
|
* loose some the data of the packet, so there you pass the maximum
|
||||||
* size for the packet you expect from the network.
|
* size for the packet you expect from the network.
|
||||||
*/
|
*/
|
||||||
Packet::Packet(NetworkSocketHandler *cs, size_t limit, size_t initial_read_size) : pos(0), limit(limit)
|
Packet::Packet(Packet::ReadTag tag, NetworkSocketHandler *cs, size_t limit, size_t initial_read_size) : pos(0), limit(limit)
|
||||||
{
|
{
|
||||||
assert(cs != nullptr);
|
assert(cs != nullptr);
|
||||||
|
|
||||||
@@ -46,18 +46,24 @@ Packet::Packet(NetworkSocketHandler *cs, size_t limit, size_t initial_read_size)
|
|||||||
* the limit as it might break things if the other side is not expecting
|
* the limit as it might break things if the other side is not expecting
|
||||||
* much larger packets than what they support.
|
* much larger packets than what they support.
|
||||||
*/
|
*/
|
||||||
Packet::Packet(PacketType type, size_t limit) : pos(0), limit(limit), cs(nullptr)
|
Packet::Packet(NetworkSocketHandler *cs, PacketType type, size_t limit) : pos(0), limit(limit), cs(cs)
|
||||||
{
|
{
|
||||||
this->ResetState(type);
|
this->ResetState(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Packet::ResetState(PacketType type)
|
void Packet::ResetState(PacketType type)
|
||||||
{
|
{
|
||||||
this->cs = nullptr;
|
|
||||||
this->buffer.clear();
|
this->buffer.clear();
|
||||||
|
|
||||||
/* Allocate space for the the size so we can write that in just before sending the packet. */
|
/* Allocate space for the the size so we can write that in just before sending the packet. */
|
||||||
this->Send_uint16(0);
|
size_t size = EncodedLengthOfPacketSize();
|
||||||
|
if (cs != nullptr && cs->send_encryption_handler != nullptr) {
|
||||||
|
/* Allocate some space for the message authentication code of the encryption. */
|
||||||
|
size += cs->send_encryption_handler->MACSize();
|
||||||
|
}
|
||||||
|
assert(this->CanWriteToPacket(size));
|
||||||
|
this->buffer.resize(size, 0);
|
||||||
|
|
||||||
this->Send_uint8(type);
|
this->Send_uint8(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,11 +72,19 @@ void Packet::ResetState(PacketType type)
|
|||||||
*/
|
*/
|
||||||
void Packet::PrepareToSend()
|
void Packet::PrepareToSend()
|
||||||
{
|
{
|
||||||
assert(this->cs == nullptr);
|
/* Prevent this to be called twice and for packets that have been received. */
|
||||||
|
assert(this->buffer[0] == 0 && this->buffer[1] == 0);
|
||||||
|
|
||||||
this->buffer[0] = GB(this->Size(), 0, 8);
|
this->buffer[0] = GB(this->Size(), 0, 8);
|
||||||
this->buffer[1] = GB(this->Size(), 8, 8);
|
this->buffer[1] = GB(this->Size(), 8, 8);
|
||||||
|
|
||||||
|
if (cs != nullptr && cs->send_encryption_handler != nullptr) {
|
||||||
|
size_t offset = EncodedLengthOfPacketSize();
|
||||||
|
size_t mac_size = cs->send_encryption_handler->MACSize();
|
||||||
|
size_t message_offset = offset + mac_size;
|
||||||
|
cs->send_encryption_handler->Encrypt(std::span(&this->buffer[offset], mac_size), std::span(&this->buffer[message_offset], this->buffer.size() - message_offset));
|
||||||
|
}
|
||||||
|
|
||||||
this->pos = 0; // We start reading from here
|
this->pos = 0; // We start reading from here
|
||||||
this->buffer.shrink_to_fit();
|
this->buffer.shrink_to_fit();
|
||||||
}
|
}
|
||||||
@@ -130,7 +144,7 @@ bool Packet::CanReadFromPacket(size_t bytes_to_read, bool close_connection)
|
|||||||
*/
|
*/
|
||||||
bool Packet::HasPacketSizeData() const
|
bool Packet::HasPacketSizeData() const
|
||||||
{
|
{
|
||||||
return this->pos >= sizeof(PacketSize);
|
return this->pos >= EncodedLengthOfPacketSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,20 +177,30 @@ bool Packet::ParsePacketSize()
|
|||||||
/* If the size of the packet is less than the bytes required for the size and type of
|
/* If the size of the packet is less than the bytes required for the size and type of
|
||||||
* the packet, or more than the allowed limit, then something is wrong with the packet.
|
* the packet, or more than the allowed limit, then something is wrong with the packet.
|
||||||
* In those cases the packet can generally be regarded as containing garbage data. */
|
* In those cases the packet can generally be regarded as containing garbage data. */
|
||||||
if (size < sizeof(PacketSize) + sizeof(PacketType) || size > this->limit) return false;
|
if (size < EncodedLengthOfPacketSize() + EncodedLengthOfPacketType() || size > this->limit) return false;
|
||||||
|
|
||||||
this->buffer.resize(size);
|
this->buffer.resize(size);
|
||||||
this->pos = sizeof(PacketSize);
|
this->pos = static_cast<PacketSize>(EncodedLengthOfPacketSize());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares the packet so it can be read
|
* Prepares the packet so it can be read
|
||||||
|
* @return True when the packet was valid, otherwise false.
|
||||||
*/
|
*/
|
||||||
void Packet::PrepareToRead()
|
bool Packet::PrepareToRead()
|
||||||
{
|
{
|
||||||
/* Put the position on the right place */
|
/* Put the position on the right place */
|
||||||
this->pos = sizeof(PacketSize);
|
this->pos = static_cast<PacketSize>(EncodedLengthOfPacketSize());
|
||||||
|
|
||||||
|
if (cs == nullptr || cs->receive_encryption_handler == nullptr) return true;
|
||||||
|
|
||||||
|
size_t mac_size = cs->receive_encryption_handler->MACSize();
|
||||||
|
if (this->buffer.size() <= pos + mac_size) return false;
|
||||||
|
|
||||||
|
bool valid = cs->receive_encryption_handler->Decrypt(std::span(&this->buffer[pos], mac_size), std::span(&this->buffer[pos + mac_size], this->buffer.size() - pos - mac_size));
|
||||||
|
this->pos += static_cast<PacketSize>(mac_size);
|
||||||
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,8 +209,10 @@ void Packet::PrepareToRead()
|
|||||||
*/
|
*/
|
||||||
PacketType Packet::GetPacketType() const
|
PacketType Packet::GetPacketType() const
|
||||||
{
|
{
|
||||||
assert(this->Size() >= sizeof(PacketSize) + sizeof(PacketType));
|
assert(this->Size() >= EncodedLengthOfPacketSize() + EncodedLengthOfPacketType());
|
||||||
return static_cast<PacketType>(buffer[sizeof(PacketSize)]);
|
size_t offset = EncodedLengthOfPacketSize();
|
||||||
|
if (cs != nullptr && cs->send_encryption_handler != nullptr) offset += cs->send_encryption_handler->MACSize();
|
||||||
|
return static_cast<PacketType>(buffer[offset]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -198,6 +224,22 @@ size_t Packet::RemainingBytesToTransfer() const
|
|||||||
return this->Size() - this->pos;
|
return this->Size() - this->pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract at most the length of the span bytes from the packet into the span.
|
||||||
|
* @param span The span to write the bytes to.
|
||||||
|
* @return The number of bytes that were actually read.
|
||||||
|
*/
|
||||||
|
size_t Packet::Recv_bytes(std::span<uint8_t> span)
|
||||||
|
{
|
||||||
|
auto tranfer_to_span = [](std::span<uint8_t> destination, const char *source, size_t amount) {
|
||||||
|
size_t to_copy = std::min(amount, destination.size());
|
||||||
|
std::copy(source, source + to_copy, destination.data());
|
||||||
|
return to_copy;
|
||||||
|
};
|
||||||
|
|
||||||
|
return this->TransferOut(tranfer_to_span, span);
|
||||||
|
}
|
||||||
|
|
||||||
bool SubPacketDeserialiser::CanDeserialiseBytes(size_t bytes_to_read, bool raise_error)
|
bool SubPacketDeserialiser::CanDeserialiseBytes(size_t bytes_to_read, bool raise_error)
|
||||||
{
|
{
|
||||||
if (this->pos + bytes_to_read > this->size) {
|
if (this->pos + bytes_to_read > this->size) {
|
||||||
|
@@ -45,6 +45,9 @@ typedef uint8_t PacketType; ///< Identifier for the packet
|
|||||||
* (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0))
|
* (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0))
|
||||||
*/
|
*/
|
||||||
struct Packet : public BufferSerialisationHelper<Packet>, public BufferDeserialisationHelper<Packet> {
|
struct Packet : public BufferSerialisationHelper<Packet>, public BufferDeserialisationHelper<Packet> {
|
||||||
|
static constexpr size_t EncodedLengthOfPacketSize() { return sizeof(PacketSize); }
|
||||||
|
static constexpr size_t EncodedLengthOfPacketType() { return sizeof(PacketType); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** The current read/write position in the packet */
|
/** The current read/write position in the packet */
|
||||||
PacketSize pos;
|
PacketSize pos;
|
||||||
@@ -57,8 +60,9 @@ private:
|
|||||||
NetworkSocketHandler *cs;
|
NetworkSocketHandler *cs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Packet(NetworkSocketHandler *cs, size_t limit, size_t initial_read_size = sizeof(PacketSize));
|
struct ReadTag{};
|
||||||
Packet(PacketType type, size_t limit = COMPAT_MTU);
|
Packet(ReadTag tag, NetworkSocketHandler *cs, size_t limit, size_t initial_read_size = EncodedLengthOfPacketSize());
|
||||||
|
Packet(NetworkSocketHandler *cs, PacketType type, size_t limit = COMPAT_MTU);
|
||||||
|
|
||||||
void ResetState(PacketType type);
|
void ResetState(PacketType type);
|
||||||
|
|
||||||
@@ -82,7 +86,7 @@ public:
|
|||||||
bool HasPacketSizeData() const;
|
bool HasPacketSizeData() const;
|
||||||
bool ParsePacketSize();
|
bool ParsePacketSize();
|
||||||
size_t Size() const;
|
size_t Size() const;
|
||||||
void PrepareToRead();
|
[[nodiscard]] bool PrepareToRead();
|
||||||
PacketType GetPacketType() const;
|
PacketType GetPacketType() const;
|
||||||
|
|
||||||
bool CanReadFromPacket(size_t bytes_to_read, bool close_connection = false);
|
bool CanReadFromPacket(size_t bytes_to_read, bool close_connection = false);
|
||||||
@@ -189,6 +193,21 @@ public:
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send as many of the bytes as possible in the packet. This can mean
|
||||||
|
* that it is possible that not all bytes are sent. To cope with this
|
||||||
|
* the function returns the span of bytes that were not sent.
|
||||||
|
* @param span The span describing the range of bytes to send.
|
||||||
|
* @return The span of bytes that were not written.
|
||||||
|
*/
|
||||||
|
std::span<const uint8_t> Send_bytes(const std::span<const uint8_t> span)
|
||||||
|
{
|
||||||
|
size_t amount = this->Send_binary_until_full(span.data(), span.data() + span.size());
|
||||||
|
return span.subspan(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Recv_bytes(std::span<uint8_t> span);
|
||||||
|
|
||||||
NetworkSocketHandler *GetParentSocket() { return this->cs; }
|
NetworkSocketHandler *GetParentSocket() { return this->cs; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -174,7 +174,7 @@ std::unique_ptr<Packet> NetworkTCPSocketHandler::ReceivePacket()
|
|||||||
if (!this->IsConnected()) return nullptr;
|
if (!this->IsConnected()) return nullptr;
|
||||||
|
|
||||||
if (this->packet_recv == nullptr) {
|
if (this->packet_recv == nullptr) {
|
||||||
this->packet_recv = std::make_unique<Packet>(this, TCP_MTU);
|
this->packet_recv = std::make_unique<Packet>(Packet::ReadTag{}, this, TCP_MTU);
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet &p = *this->packet_recv.get();
|
Packet &p = *this->packet_recv.get();
|
||||||
@@ -230,10 +230,11 @@ std::unique_ptr<Packet> NetworkTCPSocketHandler::ReceivePacket()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!p.PrepareToRead()) {
|
||||||
p.PrepareToRead();
|
DEBUG(net, 0, "Invalid packet received (too small / decryption error)");
|
||||||
|
this->CloseConnection();
|
||||||
/* Prepare for receiving a new packet */
|
return nullptr;
|
||||||
|
}
|
||||||
return std::move(this->packet_recv);
|
return std::move(this->packet_recv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,10 +33,12 @@ static const char* _packet_game_type_names[] {
|
|||||||
"SERVER_GAME_INFO",
|
"SERVER_GAME_INFO",
|
||||||
"CLIENT_GAME_INFO",
|
"CLIENT_GAME_INFO",
|
||||||
"SERVER_GAME_INFO_EXTENDED",
|
"SERVER_GAME_INFO_EXTENDED",
|
||||||
|
"SERVER_AUTH_REQUEST",
|
||||||
|
"CLIENT_AUTH_RESPONSE",
|
||||||
|
"SERVER_AUTH_COMPLETED",
|
||||||
|
"CLIENT_IDENTIFY",
|
||||||
"SERVER_CHECK_NEWGRFS",
|
"SERVER_CHECK_NEWGRFS",
|
||||||
"CLIENT_NEWGRFS_CHECKED",
|
"CLIENT_NEWGRFS_CHECKED",
|
||||||
"SERVER_NEED_GAME_PASSWORD",
|
|
||||||
"CLIENT_GAME_PASSWORD",
|
|
||||||
"SERVER_NEED_COMPANY_PASSWORD",
|
"SERVER_NEED_COMPANY_PASSWORD",
|
||||||
"CLIENT_COMPANY_PASSWORD",
|
"CLIENT_COMPANY_PASSWORD",
|
||||||
"CLIENT_SETTINGS_PASSWORD",
|
"CLIENT_SETTINGS_PASSWORD",
|
||||||
@@ -153,9 +155,11 @@ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet &p)
|
|||||||
case PACKET_SERVER_GAME_INFO: return this->Receive_SERVER_GAME_INFO(p);
|
case PACKET_SERVER_GAME_INFO: return this->Receive_SERVER_GAME_INFO(p);
|
||||||
case PACKET_SERVER_GAME_INFO_EXTENDED: return this->Receive_SERVER_GAME_INFO_EXTENDED(p);
|
case PACKET_SERVER_GAME_INFO_EXTENDED: return this->Receive_SERVER_GAME_INFO_EXTENDED(p);
|
||||||
case PACKET_SERVER_CLIENT_INFO: return this->Receive_SERVER_CLIENT_INFO(p);
|
case PACKET_SERVER_CLIENT_INFO: return this->Receive_SERVER_CLIENT_INFO(p);
|
||||||
case PACKET_SERVER_NEED_GAME_PASSWORD: return this->Receive_SERVER_NEED_GAME_PASSWORD(p);
|
case PACKET_CLIENT_IDENTIFY: return this->Receive_CLIENT_IDENTIFY(p);
|
||||||
|
case PACKET_SERVER_AUTH_REQUEST: return this->Receive_SERVER_AUTH_REQUEST(p);
|
||||||
case PACKET_SERVER_NEED_COMPANY_PASSWORD: return this->Receive_SERVER_NEED_COMPANY_PASSWORD(p);
|
case PACKET_SERVER_NEED_COMPANY_PASSWORD: return this->Receive_SERVER_NEED_COMPANY_PASSWORD(p);
|
||||||
case PACKET_CLIENT_GAME_PASSWORD: return this->Receive_CLIENT_GAME_PASSWORD(p);
|
case PACKET_CLIENT_AUTH_RESPONSE: return this->Receive_CLIENT_AUTH_RESPONSE(p);
|
||||||
|
case PACKET_SERVER_ENABLE_ENCRYPTION: return this->Receive_SERVER_ENABLE_ENCRYPTION(p);
|
||||||
case PACKET_CLIENT_COMPANY_PASSWORD: return this->Receive_CLIENT_COMPANY_PASSWORD(p);
|
case PACKET_CLIENT_COMPANY_PASSWORD: return this->Receive_CLIENT_COMPANY_PASSWORD(p);
|
||||||
case PACKET_CLIENT_SETTINGS_PASSWORD: return this->Receive_CLIENT_SETTINGS_PASSWORD(p);
|
case PACKET_CLIENT_SETTINGS_PASSWORD: return this->Receive_CLIENT_SETTINGS_PASSWORD(p);
|
||||||
case PACKET_SERVER_SETTINGS_ACCESS: return this->Receive_SERVER_SETTINGS_ACCESS(p);
|
case PACKET_SERVER_SETTINGS_ACCESS: return this->Receive_SERVER_SETTINGS_ACCESS(p);
|
||||||
@@ -233,57 +237,59 @@ NetworkRecvStatus NetworkGameSocketHandler::ReceiveInvalidPacket(PacketGameType
|
|||||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_FULL(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_FULL); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_FULL(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_FULL); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_BANNED(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_BANNED); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_BANNED(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_BANNED); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_JOIN); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_JOIN); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_INFO(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_INFO); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_INFO(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_INFO); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_GAME_INFO); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_GAME_INFO); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_GAME_INFO_EXTENDED(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_GAME_INFO_EXTENDED); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_GAME_INFO_EXTENDED(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_GAME_INFO_EXTENDED); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CLIENT_INFO); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_CLIENT_INFO); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_GAME_PASSWORD); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_IDENTIFY(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_IDENTIFY); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_COMPANY_PASSWORD); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_AUTH_REQUEST(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_AUTH_REQUEST); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_PASSWORD); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_COMPANY_PASSWORD); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMPANY_PASSWORD); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_AUTH_RESPONSE(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_AUTH_RESPONSE); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SETTINGS_PASSWORD(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SETTINGS_PASSWORD); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ENABLE_ENCRYPTION(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_ENABLE_ENCRYPTION); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SETTINGS_ACCESS(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SETTINGS_ACCESS); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMPANY_PASSWORD); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WELCOME); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SETTINGS_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SETTINGS_PASSWORD); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GETMAP); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SETTINGS_ACCESS(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_SETTINGS_ACCESS); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WAIT(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WAIT); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_WELCOME); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_BEGIN(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_BEGIN); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GETMAP); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_SIZE(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_SIZE); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WAIT(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_WAIT); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_DATA(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_DATA); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_BEGIN(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_BEGIN); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_DONE); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_SIZE(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_SIZE); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_MAP_OK); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_DATA(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_DATA); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_JOIN(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_JOIN); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_DONE); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_FRAME(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_FRAME); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_MAP_OK); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SYNC(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SYNC); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_JOIN(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_JOIN); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ACK(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ACK); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_FRAME(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_FRAME); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMMAND); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SYNC(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_SYNC); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMMAND); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ACK(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ACK); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_CHAT); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMMAND); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CHAT(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CHAT); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMMAND); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_EXTERNAL_CHAT(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_EXTERNAL_CHAT); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_CHAT); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_PASSWORD(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SET_PASSWORD); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CHAT(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_CHAT); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SET_NAME); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_EXTERNAL_CHAT(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_EXTERNAL_CHAT); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_QUIT); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SET_PASSWORD); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ERROR); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SET_NAME); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_DESYNC_LOG(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_DESYNC_LOG); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_QUIT); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_DESYNC_LOG(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_DESYNC_LOG); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ERROR); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_DESYNC_MSG(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_DESYNC_LOG); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_DESYNC_LOG(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_DESYNC_LOG); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_DESYNC_SYNC_DATA(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_DESYNC_SYNC_DATA); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_DESYNC_LOG(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_DESYNC_LOG); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_QUIT(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_QUIT); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_DESYNC_MSG(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_DESYNC_LOG); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR_QUIT); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_DESYNC_SYNC_DATA(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_DESYNC_SYNC_DATA); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SHUTDOWN); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_QUIT(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_QUIT); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEWGAME(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEWGAME); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR_QUIT); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_RCON(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_RCON); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_SHUTDOWN); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_RCON(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_RCON); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEWGAME(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEWGAME); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CHECK_NEWGRFS); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_RCON(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_RCON); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_NEWGRFS_CHECKED); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_RCON(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_RCON); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MOVE(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MOVE); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_CHECK_NEWGRFS); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet &p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_MOVE); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_NEWGRFS_CHECKED); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMPANY_UPDATE); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MOVE(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_MOVE); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CONFIG_UPDATE(Packet &p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CONFIG_UPDATE); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_MOVE); }
|
||||||
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMPANY_UPDATE); }
|
||||||
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CONFIG_UPDATE(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_CONFIG_UPDATE); }
|
||||||
|
|
||||||
std::string NetworkGameSocketHandler::GetDebugInfo() const { return ""; }
|
std::string NetworkGameSocketHandler::GetDebugInfo() const { return ""; }
|
||||||
|
|
||||||
|
@@ -60,13 +60,19 @@ enum PacketGameType : uint8_t {
|
|||||||
|
|
||||||
PACKET_SERVER_GAME_INFO_EXTENDED, ///< Information about the server (extended). Note that the server should not use this ID directly.
|
PACKET_SERVER_GAME_INFO_EXTENDED, ///< Information about the server (extended). Note that the server should not use this ID directly.
|
||||||
|
|
||||||
|
/* After the join step, the first perform game authentication and enabling encryption. */
|
||||||
|
PACKET_SERVER_AUTH_REQUEST, ///< The server requests the client to authenticate using a number of methods.
|
||||||
|
PACKET_CLIENT_AUTH_RESPONSE, ///< The client responds to the authentication request.
|
||||||
|
PACKET_SERVER_ENABLE_ENCRYPTION, ///< The server tells that authentication has completed and requests to enable encryption with the keys of the last \c PACKET_CLIENT_AUTH_RESPONSE.
|
||||||
|
|
||||||
|
/* After the authentication is done, the next step is identification. */
|
||||||
|
PACKET_CLIENT_IDENTIFY, ///< Client telling the server the client's name and requested company.
|
||||||
|
|
||||||
/* After the join step, the first is checking NewGRFs. */
|
/* After the join step, the first is checking NewGRFs. */
|
||||||
PACKET_SERVER_CHECK_NEWGRFS, ///< Server sends NewGRF IDs and MD5 checksums for the client to check.
|
PACKET_SERVER_CHECK_NEWGRFS, ///< Server sends NewGRF IDs and MD5 checksums for the client to check.
|
||||||
PACKET_CLIENT_NEWGRFS_CHECKED, ///< Client acknowledges that it has all required NewGRFs.
|
PACKET_CLIENT_NEWGRFS_CHECKED, ///< Client acknowledges that it has all required NewGRFs.
|
||||||
|
|
||||||
/* Checking the game, and then company passwords. */
|
/* Checking the company passwords. */
|
||||||
PACKET_SERVER_NEED_GAME_PASSWORD, ///< Server requests the (hashed) game password.
|
|
||||||
PACKET_CLIENT_GAME_PASSWORD, ///< Clients sends the (hashed) game password.
|
|
||||||
PACKET_SERVER_NEED_COMPANY_PASSWORD, ///< Server requests the (hashed) company password.
|
PACKET_SERVER_NEED_COMPANY_PASSWORD, ///< Server requests the (hashed) company password.
|
||||||
PACKET_CLIENT_COMPANY_PASSWORD, ///< Client sends the (hashed) company password.
|
PACKET_CLIENT_COMPANY_PASSWORD, ///< Client sends the (hashed) company password.
|
||||||
PACKET_CLIENT_SETTINGS_PASSWORD, ///< Client sends the (hashed) settings password.
|
PACKET_CLIENT_SETTINGS_PASSWORD, ///< Client sends the (hashed) settings password.
|
||||||
@@ -220,10 +226,21 @@ protected:
|
|||||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p);
|
virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indication to the client that the server needs a game password.
|
* The client tells the server about the identity of the client:
|
||||||
|
* string Name of the client (max NETWORK_NAME_LENGTH).
|
||||||
|
* uint8_t ID of the company to play as (1..MAX_COMPANIES).
|
||||||
* @param p The packet that was just received.
|
* @param p The packet that was just received.
|
||||||
*/
|
*/
|
||||||
virtual NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet &p);
|
virtual NetworkRecvStatus Receive_CLIENT_IDENTIFY(Packet &p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indication to the client that it needs to authenticate:
|
||||||
|
* bool Whether to use the password in the key exchange.
|
||||||
|
* 32 * uint8_t Public key of the server.
|
||||||
|
* 24 * uint8_t Nonce for the key exchange.
|
||||||
|
* @param p The packet that was just received.
|
||||||
|
*/
|
||||||
|
virtual NetworkRecvStatus Receive_SERVER_AUTH_REQUEST(Packet &p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indication to the client that the server needs a company password:
|
* Indication to the client that the server needs a company password:
|
||||||
@@ -234,12 +251,19 @@ protected:
|
|||||||
virtual NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p);
|
virtual NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a password to the server to authorize:
|
* Send the response to the authentication request:
|
||||||
* uint8_t Password type (see NetworkPasswordType).
|
* 32 * uint8_t Public key of the client.
|
||||||
* string The password.
|
* 8 * uint8_t Random message that got encoded and signed.
|
||||||
|
* 16 * uint8_t Message authentication code.
|
||||||
* @param p The packet that was just received.
|
* @param p The packet that was just received.
|
||||||
*/
|
*/
|
||||||
virtual NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet &p);
|
virtual NetworkRecvStatus Receive_CLIENT_AUTH_RESPONSE(Packet &p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indication to the client that authentication is complete and encryption has to be used from here on forward.
|
||||||
|
* @param p The packet that was just received.
|
||||||
|
*/
|
||||||
|
virtual NetworkRecvStatus Receive_SERVER_ENABLE_ENCRYPTION(Packet &p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a password to the server to authorize
|
* Send a password to the server to authorize
|
||||||
|
@@ -35,7 +35,7 @@ public:
|
|||||||
/* Check if the client is banned. */
|
/* Check if the client is banned. */
|
||||||
for (const auto &entry : _network_ban_list) {
|
for (const auto &entry : _network_ban_list) {
|
||||||
if (address.IsInNetmask(entry.c_str())) {
|
if (address.IsInNetmask(entry.c_str())) {
|
||||||
Packet p(Tban_packet);
|
Packet p(nullptr, Tban_packet);
|
||||||
p.PrepareToSend();
|
p.PrepareToSend();
|
||||||
|
|
||||||
DEBUG(net, 2, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), entry.c_str());
|
DEBUG(net, 2, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), entry.c_str());
|
||||||
@@ -52,7 +52,7 @@ public:
|
|||||||
if (!Tsocket::AllowConnection()) {
|
if (!Tsocket::AllowConnection()) {
|
||||||
/* No more clients allowed?
|
/* No more clients allowed?
|
||||||
* Send to the client that we are full! */
|
* Send to the client that we are full! */
|
||||||
Packet p(Tfull_packet);
|
Packet p(nullptr, Tfull_packet);
|
||||||
p.PrepareToSend();
|
p.PrepareToSend();
|
||||||
|
|
||||||
if (p.TransferOut<int>(send, s, 0) < 0) {
|
if (p.TransferOut<int>(send, s, 0) < 0) {
|
||||||
|
@@ -88,7 +88,7 @@ void NetworkUDPSocketHandler::SendPacket(Packet &p, NetworkAddress &recv, bool a
|
|||||||
const size_t packet_size = p.Size();
|
const size_t packet_size = p.Size();
|
||||||
const uint8_t frag_count = (uint8_t)((packet_size + PAYLOAD_MTU - 1) / PAYLOAD_MTU);
|
const uint8_t frag_count = (uint8_t)((packet_size + PAYLOAD_MTU - 1) / PAYLOAD_MTU);
|
||||||
|
|
||||||
Packet frag(PACKET_UDP_EX_MULTI);
|
Packet frag(this, PACKET_UDP_EX_MULTI);
|
||||||
uint8_t current_frag = 0;
|
uint8_t current_frag = 0;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
while (offset < packet_size) {
|
while (offset < packet_size) {
|
||||||
@@ -147,7 +147,7 @@ void NetworkUDPSocketHandler::ReceivePackets()
|
|||||||
memset(&client_addr, 0, sizeof(client_addr));
|
memset(&client_addr, 0, sizeof(client_addr));
|
||||||
|
|
||||||
/* The limit is UDP_MTU, but also allocate that much as we need to read the whole packet in one go. */
|
/* The limit is UDP_MTU, but also allocate that much as we need to read the whole packet in one go. */
|
||||||
Packet p(this, UDP_MTU, UDP_MTU);
|
Packet p(Packet::ReadTag{}, this, UDP_MTU, UDP_MTU);
|
||||||
socklen_t client_len = sizeof(client_addr);
|
socklen_t client_len = sizeof(client_addr);
|
||||||
|
|
||||||
/* Try to receive anything */
|
/* Try to receive anything */
|
||||||
@@ -169,7 +169,10 @@ void NetworkUDPSocketHandler::ReceivePackets()
|
|||||||
DEBUG(net, 1, "received a packet with mismatching size from %s, (%u, %u)", NetworkAddressDumper().GetAddressAsString(&address), (uint)nbytes, (uint)p.Size());
|
DEBUG(net, 1, "received a packet with mismatching size from %s, (%u, %u)", NetworkAddressDumper().GetAddressAsString(&address), (uint)nbytes, (uint)p.Size());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
p.PrepareToRead();
|
if (!p.PrepareToRead()) {
|
||||||
|
DEBUG(net, 1, "Invalid packet received (too small / decryption error)");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle the packet */
|
/* Handle the packet */
|
||||||
this->HandleUDPPacket(p, address);
|
this->HandleUDPPacket(p, address);
|
||||||
@@ -236,13 +239,13 @@ void NetworkUDPSocketHandler::Receive_EX_MULTI(Packet &p, NetworkAddress &client
|
|||||||
DEBUG(net, 6, "[udp] merged multi-part packet from %s: " OTTD_PRINTFHEX64 ", %u bytes",
|
DEBUG(net, 6, "[udp] merged multi-part packet from %s: " OTTD_PRINTFHEX64 ", %u bytes",
|
||||||
NetworkAddressDumper().GetAddressAsString(client_addr), token, total_payload);
|
NetworkAddressDumper().GetAddressAsString(client_addr), token, total_payload);
|
||||||
|
|
||||||
Packet merged(this, TCP_MTU, 0);
|
Packet merged(Packet::ReadTag{}, this, TCP_MTU, 0);
|
||||||
merged.ReserveBuffer(total_payload);
|
merged.ReserveBuffer(total_payload);
|
||||||
for (auto &frag : fs.fragments) {
|
for (auto &frag : fs.fragments) {
|
||||||
merged.Send_binary((const uint8_t *)frag.data(), frag.size());
|
merged.Send_binary((const uint8_t *)frag.data(), frag.size());
|
||||||
}
|
}
|
||||||
merged.ParsePacketSize();
|
merged.ParsePacketSize();
|
||||||
merged.PrepareToRead();
|
if (!merged.PrepareToRead()) return;
|
||||||
|
|
||||||
/* If the size does not match the packet must be corrupted.
|
/* If the size does not match the packet must be corrupted.
|
||||||
* Otherwise it will be marked as corrupted later on. */
|
* Otherwise it will be marked as corrupted later on. */
|
||||||
|
@@ -386,6 +386,7 @@ StringID GetNetworkErrorMsg(NetworkErrorCode err)
|
|||||||
STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP,
|
STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP,
|
||||||
STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN,
|
STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN,
|
||||||
STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME,
|
STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME,
|
||||||
|
STR_NETWORK_ERROR_CLIENT_NOT_ON_ALLOW_LIST,
|
||||||
};
|
};
|
||||||
static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
|
static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
|
||||||
|
|
||||||
|
@@ -135,7 +135,7 @@ ServerNetworkAdminSocketHandler::~ServerNetworkAdminSocketHandler()
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendError(NetworkErrorCode error)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendError(NetworkErrorCode error)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_ERROR);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_ERROR);
|
||||||
|
|
||||||
p->Send_uint8(error);
|
p->Send_uint8(error);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -150,7 +150,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendError(NetworkErrorCode er
|
|||||||
/** Send the protocol version to the admin. */
|
/** Send the protocol version to the admin. */
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendProtocol()
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendProtocol()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_PROTOCOL);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_PROTOCOL);
|
||||||
|
|
||||||
/* announce the protocol version */
|
/* announce the protocol version */
|
||||||
p->Send_uint8(NETWORK_GAME_ADMIN_VERSION);
|
p->Send_uint8(NETWORK_GAME_ADMIN_VERSION);
|
||||||
@@ -170,7 +170,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendProtocol()
|
|||||||
/** Send a welcome message to the admin. */
|
/** Send a welcome message to the admin. */
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome()
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_WELCOME);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_WELCOME);
|
||||||
|
|
||||||
p->Send_string(_settings_client.network.server_name);
|
p->Send_string(_settings_client.network.server_name);
|
||||||
p->Send_string(_openttd_revision);
|
p->Send_string(_openttd_revision);
|
||||||
@@ -191,7 +191,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome()
|
|||||||
/** Tell the admin we started a new game. */
|
/** Tell the admin we started a new game. */
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendNewGame()
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendNewGame()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_NEWGAME);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_NEWGAME);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -199,7 +199,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendNewGame()
|
|||||||
/** Tell the admin we're shutting down. */
|
/** Tell the admin we're shutting down. */
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendShutdown()
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendShutdown()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_SHUTDOWN);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_SHUTDOWN);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendShutdown()
|
|||||||
/** Tell the admin the date. */
|
/** Tell the admin the date. */
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendDate()
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendDate()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_DATE);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_DATE);
|
||||||
|
|
||||||
p->Send_uint32(CalTime::CurDate().base());
|
p->Send_uint32(CalTime::CurDate().base());
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -221,7 +221,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendDate()
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientJoin(ClientID client_id)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientJoin(ClientID client_id)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CLIENT_JOIN);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_CLIENT_JOIN);
|
||||||
|
|
||||||
p->Send_uint32(client_id);
|
p->Send_uint32(client_id);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -239,7 +239,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkC
|
|||||||
/* Only send data when we're a proper client, not just someone trying to query the server. */
|
/* Only send data when we're a proper client, not just someone trying to query the server. */
|
||||||
if (ci == nullptr) return NETWORK_RECV_STATUS_OKAY;
|
if (ci == nullptr) return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CLIENT_INFO);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_CLIENT_INFO);
|
||||||
|
|
||||||
p->Send_uint32(ci->client_id);
|
p->Send_uint32(ci->client_id);
|
||||||
p->Send_string(cs == nullptr ? "" : const_cast<NetworkAddress &>(cs->client_address).GetHostname());
|
p->Send_string(cs == nullptr ? "" : const_cast<NetworkAddress &>(cs->client_address).GetHostname());
|
||||||
@@ -260,7 +260,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkC
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientUpdate(const NetworkClientInfo *ci)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientUpdate(const NetworkClientInfo *ci)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CLIENT_UPDATE);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_CLIENT_UPDATE);
|
||||||
|
|
||||||
p->Send_uint32(ci->client_id);
|
p->Send_uint32(ci->client_id);
|
||||||
p->Send_string(ci->client_name);
|
p->Send_string(ci->client_name);
|
||||||
@@ -277,7 +277,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientUpdate(const Networ
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientQuit(ClientID client_id)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientQuit(ClientID client_id)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CLIENT_QUIT);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_CLIENT_QUIT);
|
||||||
|
|
||||||
p->Send_uint32(client_id);
|
p->Send_uint32(client_id);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -292,7 +292,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientQuit(ClientID clien
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientError(ClientID client_id, NetworkErrorCode error)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientError(ClientID client_id, NetworkErrorCode error)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CLIENT_ERROR);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_CLIENT_ERROR);
|
||||||
|
|
||||||
p->Send_uint32(client_id);
|
p->Send_uint32(client_id);
|
||||||
p->Send_uint8 (error);
|
p->Send_uint8 (error);
|
||||||
@@ -307,7 +307,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientError(ClientID clie
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyNew(CompanyID company_id)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyNew(CompanyID company_id)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_NEW);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_COMPANY_NEW);
|
||||||
p->Send_uint8(company_id);
|
p->Send_uint8(company_id);
|
||||||
|
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -321,7 +321,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyNew(CompanyID comp
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company *c)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company *c)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_INFO);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_COMPANY_INFO);
|
||||||
|
|
||||||
p->Send_uint8 (c->index);
|
p->Send_uint8 (c->index);
|
||||||
SetDParam(0, c->index);
|
SetDParam(0, c->index);
|
||||||
@@ -346,7 +346,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Company *c)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Company *c)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_UPDATE);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_COMPANY_UPDATE);
|
||||||
|
|
||||||
p->Send_uint8 (c->index);
|
p->Send_uint8 (c->index);
|
||||||
SetDParam(0, c->index);
|
SetDParam(0, c->index);
|
||||||
@@ -369,7 +369,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Compa
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason acrr)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason acrr)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_REMOVE);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_COMPANY_REMOVE);
|
||||||
|
|
||||||
p->Send_uint8(company_id);
|
p->Send_uint8(company_id);
|
||||||
p->Send_uint8(acrr);
|
p->Send_uint8(acrr);
|
||||||
@@ -386,7 +386,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyEconomy()
|
|||||||
/* Get the income. */
|
/* Get the income. */
|
||||||
Money income = -std::reduce(std::begin(company->yearly_expenses[0]), std::end(company->yearly_expenses[0]));
|
Money income = -std::reduce(std::begin(company->yearly_expenses[0]), std::end(company->yearly_expenses[0]));
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_ECONOMY);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_COMPANY_ECONOMY);
|
||||||
|
|
||||||
p->Send_uint8(company->index);
|
p->Send_uint8(company->index);
|
||||||
|
|
||||||
@@ -419,7 +419,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyStats()
|
|||||||
|
|
||||||
/* Go through all the companies. */
|
/* Go through all the companies. */
|
||||||
for (const Company *company : Company::Iterate()) {
|
for (const Company *company : Company::Iterate()) {
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_COMPANY_STATS);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_COMPANY_STATS);
|
||||||
|
|
||||||
/* Send the information. */
|
/* Send the information. */
|
||||||
p->Send_uint8(company->index);
|
p->Send_uint8(company->index);
|
||||||
@@ -448,7 +448,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyStats()
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, NetworkTextMessageData data)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, NetworkTextMessageData data)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CHAT);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_CHAT);
|
||||||
|
|
||||||
p->Send_uint8 (action);
|
p->Send_uint8 (action);
|
||||||
p->Send_uint8 (desttype);
|
p->Send_uint8 (desttype);
|
||||||
@@ -466,7 +466,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendChat(NetworkAction action
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRconEnd(const std::string_view command)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRconEnd(const std::string_view command)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_RCON_END);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_RCON_END);
|
||||||
|
|
||||||
p->Send_string(command);
|
p->Send_string(command);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -481,7 +481,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRconEnd(const std::string
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRcon(uint16_t colour, const std::string_view result)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRcon(uint16_t colour, const std::string_view result)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_RCON);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_RCON);
|
||||||
|
|
||||||
p->Send_uint16(colour);
|
p->Send_uint16(colour);
|
||||||
p->Send_string(result);
|
p->Send_string(result);
|
||||||
@@ -540,7 +540,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendConsole(const std::string
|
|||||||
* smaller than COMPAT_MTU. */
|
* smaller than COMPAT_MTU. */
|
||||||
if (origin.size() + string.size() + 2 + 3 >= COMPAT_MTU) return NETWORK_RECV_STATUS_OKAY;
|
if (origin.size() + string.size() + 2 + 3 >= COMPAT_MTU) return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CONSOLE);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_CONSOLE);
|
||||||
|
|
||||||
p->Send_string(origin);
|
p->Send_string(origin);
|
||||||
p->Send_string(string);
|
p->Send_string(string);
|
||||||
@@ -555,7 +555,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendConsole(const std::string
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendGameScript(const std::string_view json)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendGameScript(const std::string_view json)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_GAMESCRIPT);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_GAMESCRIPT);
|
||||||
|
|
||||||
p->Send_string(json);
|
p->Send_string(json);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -566,7 +566,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendGameScript(const std::str
|
|||||||
/** Send ping-reply (pong) to admin **/
|
/** Send ping-reply (pong) to admin **/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendPong(uint32_t d1)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendPong(uint32_t d1)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_PONG);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_PONG);
|
||||||
|
|
||||||
p->Send_uint32(d1);
|
p->Send_uint32(d1);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -577,7 +577,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendPong(uint32_t d1)
|
|||||||
/** Send the names of the commands. */
|
/** Send the names of the commands. */
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdNames()
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdNames()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CMD_NAMES);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_CMD_NAMES);
|
||||||
|
|
||||||
for (uint i = 0; i < CMD_END; i++) {
|
for (uint i = 0; i < CMD_END; i++) {
|
||||||
const char *cmdname = GetCommandName(i);
|
const char *cmdname = GetCommandName(i);
|
||||||
@@ -589,7 +589,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdNames()
|
|||||||
p->Send_bool(false);
|
p->Send_bool(false);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
|
|
||||||
p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CMD_NAMES);
|
p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_CMD_NAMES);
|
||||||
}
|
}
|
||||||
|
|
||||||
p->Send_bool(true);
|
p->Send_bool(true);
|
||||||
@@ -611,7 +611,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdNames()
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdLogging(ClientID client_id, const CommandPacket &cp)
|
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdLogging(ClientID client_id, const CommandPacket &cp)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(ADMIN_PACKET_SERVER_CMD_LOGGING);
|
auto p = std::make_unique<Packet>(this, ADMIN_PACKET_SERVER_CMD_LOGGING);
|
||||||
|
|
||||||
p->Send_uint32(client_id);
|
p->Send_uint32(client_id);
|
||||||
p->Send_uint8 (cp.company);
|
p->Send_uint8 (cp.company);
|
||||||
|
@@ -458,7 +458,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendKeyPasswordPacket(PacketTy
|
|||||||
static_assert(std::tuple_size<decltype(ss.shared_data)>::value == 64);
|
static_assert(std::tuple_size<decltype(ss.shared_data)>::value == 64);
|
||||||
crypto_aead_lock(message.data(), mac.data(), ss.shared_data.data(), nonce.data(), keys.x25519_pub_key.data(), keys.x25519_pub_key.size(), message.data(), message.size());
|
crypto_aead_lock(message.data(), mac.data(), ss.shared_data.data(), nonce.data(), keys.x25519_pub_key.data(), keys.x25519_pub_key.size(), message.data(), message.size());
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(packet_type, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, packet_type, TCP_MTU);
|
||||||
static_assert(std::tuple_size<decltype(keys.x25519_pub_key)>::value == 32);
|
static_assert(std::tuple_size<decltype(keys.x25519_pub_key)>::value == 32);
|
||||||
p->Send_binary(keys.x25519_pub_key);
|
p->Send_binary(keys.x25519_pub_key);
|
||||||
p->Send_binary(nonce);
|
p->Send_binary(nonce);
|
||||||
@@ -482,9 +482,17 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendJoin()
|
|||||||
_network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING;
|
_network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING;
|
||||||
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_JOIN);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_JOIN);
|
||||||
p->Send_string(_openttd_revision);
|
p->Send_string(_openttd_revision);
|
||||||
p->Send_uint32(_openttd_newgrf_version);
|
p->Send_uint32(_openttd_newgrf_version);
|
||||||
|
my_client->SendPacket(std::move(p));
|
||||||
|
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendIdentify()
|
||||||
|
{
|
||||||
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_IDENTIFY, TCP_MTU);
|
||||||
p->Send_string(_settings_client.network.client_name); // Client name
|
p->Send_string(_settings_client.network.client_name); // Client name
|
||||||
p->Send_uint8 (_network_join.company); // PlayAs
|
p->Send_uint8 (_network_join.company); // PlayAs
|
||||||
p->Send_uint8 (0); // Used to be language
|
p->Send_uint8 (0); // Used to be language
|
||||||
@@ -495,7 +503,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendJoin()
|
|||||||
/** Tell the server we got all the NewGRFs. */
|
/** Tell the server we got all the NewGRFs. */
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendNewGRFsOk()
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendNewGRFsOk()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_NEWGRFS_CHECKED);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_NEWGRFS_CHECKED, TCP_MTU);
|
||||||
my_client->SendPacket(std::move(p));
|
my_client->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -504,10 +512,13 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendNewGRFsOk()
|
|||||||
* Set the game password as requested.
|
* Set the game password as requested.
|
||||||
* @param password The game password.
|
* @param password The game password.
|
||||||
*/
|
*/
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const std::string &password)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendAuthResponse()
|
||||||
{
|
{
|
||||||
NetworkSharedSecrets ss;
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_AUTH_RESPONSE, TCP_MTU);
|
||||||
return my_client->SendKeyPasswordPacket(PACKET_CLIENT_GAME_PASSWORD, ss, password, nullptr);
|
my_client->authentication_handler->SendResponse(*p);
|
||||||
|
my_client->SendPacket(std::move(p));
|
||||||
|
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -516,7 +527,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const std::st
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const std::string &password)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const std::string &password)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_COMPANY_PASSWORD, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_COMPANY_PASSWORD, TCP_MTU);
|
||||||
p->Send_string(GenerateCompanyPasswordHash(password, _company_password_server_id, _company_password_game_seed));
|
p->Send_string(GenerateCompanyPasswordHash(password, _company_password_server_id, _company_password_game_seed));
|
||||||
my_client->SendPacket(std::move(p));
|
my_client->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
@@ -529,7 +540,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const std:
|
|||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendSettingsPassword(const std::string &password)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendSettingsPassword(const std::string &password)
|
||||||
{
|
{
|
||||||
if (password.empty()) {
|
if (password.empty()) {
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_SETTINGS_PASSWORD, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_SETTINGS_PASSWORD, TCP_MTU);
|
||||||
my_client->SendPacket(std::move(p));
|
my_client->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
} else {
|
} else {
|
||||||
@@ -543,7 +554,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGetMap()
|
|||||||
{
|
{
|
||||||
my_client->status = STATUS_MAP_WAIT;
|
my_client->status = STATUS_MAP_WAIT;
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_GETMAP, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_GETMAP, TCP_MTU);
|
||||||
#if defined(WITH_ZSTD)
|
#if defined(WITH_ZSTD)
|
||||||
p->Send_bool(true);
|
p->Send_bool(true);
|
||||||
#else
|
#else
|
||||||
@@ -558,7 +569,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMapOk()
|
|||||||
{
|
{
|
||||||
my_client->status = STATUS_ACTIVE;
|
my_client->status = STATUS_ACTIVE;
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_MAP_OK, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_MAP_OK, TCP_MTU);
|
||||||
my_client->SendPacket(std::move(p));
|
my_client->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -566,7 +577,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMapOk()
|
|||||||
/** Send an acknowledgement from the server's ticks. */
|
/** Send an acknowledgement from the server's ticks. */
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendAck()
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendAck()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_ACK, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_ACK, TCP_MTU);
|
||||||
|
|
||||||
p->Send_uint32(_frame_counter);
|
p->Send_uint32(_frame_counter);
|
||||||
p->Send_uint8 (my_client->token);
|
p->Send_uint8 (my_client->token);
|
||||||
@@ -580,7 +591,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendAck()
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCommand(const CommandPacket &cp)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCommand(const CommandPacket &cp)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_COMMAND, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_COMMAND, TCP_MTU);
|
||||||
my_client->NetworkGameSocketHandler::SendCommand(*p, cp);
|
my_client->NetworkGameSocketHandler::SendCommand(*p, cp);
|
||||||
|
|
||||||
my_client->SendPacket(std::move(p));
|
my_client->SendPacket(std::move(p));
|
||||||
@@ -591,7 +602,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendCommand(const CommandPacke
|
|||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendChat(NetworkAction action, DestType type, int dest, const std::string &msg, NetworkTextMessageData data)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendChat(NetworkAction action, DestType type, int dest, const std::string &msg, NetworkTextMessageData data)
|
||||||
{
|
{
|
||||||
if (!my_client) return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
if (!my_client) return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_CHAT, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_CHAT, TCP_MTU);
|
||||||
|
|
||||||
p->Send_uint8 (action);
|
p->Send_uint8 (action);
|
||||||
p->Send_uint8 (type);
|
p->Send_uint8 (type);
|
||||||
@@ -606,7 +617,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendChat(NetworkAction action,
|
|||||||
/** Send an error-packet over the network */
|
/** Send an error-packet over the network */
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendError(NetworkErrorCode errorno, NetworkRecvStatus recvstatus)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendError(NetworkErrorCode errorno, NetworkRecvStatus recvstatus)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_ERROR, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_ERROR, TCP_MTU);
|
||||||
|
|
||||||
p->Send_uint8(errorno);
|
p->Send_uint8(errorno);
|
||||||
p->Send_uint8(recvstatus);
|
p->Send_uint8(recvstatus);
|
||||||
@@ -620,7 +631,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendError(NetworkErrorCode err
|
|||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendDesyncLog(const std::string &log)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendDesyncLog(const std::string &log)
|
||||||
{
|
{
|
||||||
for (size_t offset = 0; offset < log.size();) {
|
for (size_t offset = 0; offset < log.size();) {
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_DESYNC_LOG, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_DESYNC_LOG, TCP_MTU);
|
||||||
size_t size = std::min<size_t>(log.size() - offset, TCP_MTU - 2 - p->Size());
|
size_t size = std::min<size_t>(log.size() - offset, TCP_MTU - 2 - p->Size());
|
||||||
p->Send_uint16((uint16_t)size);
|
p->Send_uint16((uint16_t)size);
|
||||||
p->Send_binary((const uint8_t *)(log.data() + offset), size);
|
p->Send_binary((const uint8_t *)(log.data() + offset), size);
|
||||||
@@ -634,7 +645,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendDesyncLog(const std::strin
|
|||||||
/** Send an error-packet over the network */
|
/** Send an error-packet over the network */
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendDesyncMessage(const char *msg)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendDesyncMessage(const char *msg)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_DESYNC_MSG, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_DESYNC_MSG, TCP_MTU);
|
||||||
p->Send_uint32(EconTime::CurDate().base());
|
p->Send_uint32(EconTime::CurDate().base());
|
||||||
p->Send_uint16(EconTime::CurDateFract());
|
p->Send_uint16(EconTime::CurDateFract());
|
||||||
p->Send_uint8(TickSkipCounter());
|
p->Send_uint8(TickSkipCounter());
|
||||||
@@ -658,7 +669,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendDesyncSyncData()
|
|||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_DESYNC_SYNC_DATA, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_DESYNC_SYNC_DATA, TCP_MTU);
|
||||||
p->Send_uint32((uint32_t)_network_sync_record_counts.size());
|
p->Send_uint32((uint32_t)_network_sync_record_counts.size());
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
for (uint32_t count : _network_sync_record_counts) {
|
for (uint32_t count : _network_sync_record_counts) {
|
||||||
@@ -681,7 +692,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendDesyncSyncData()
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetPassword(const std::string &password)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetPassword(const std::string &password)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_SET_PASSWORD, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_SET_PASSWORD, TCP_MTU);
|
||||||
|
|
||||||
p->Send_string(GenerateCompanyPasswordHash(password, _company_password_server_id, _company_password_game_seed));
|
p->Send_string(GenerateCompanyPasswordHash(password, _company_password_server_id, _company_password_game_seed));
|
||||||
my_client->SendPacket(std::move(p));
|
my_client->SendPacket(std::move(p));
|
||||||
@@ -694,7 +705,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetPassword(const std::str
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetName(const std::string &name)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetName(const std::string &name)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_SET_NAME, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_SET_NAME, TCP_MTU);
|
||||||
|
|
||||||
p->Send_string(name);
|
p->Send_string(name);
|
||||||
my_client->SendPacket(std::move(p));
|
my_client->SendPacket(std::move(p));
|
||||||
@@ -706,7 +717,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetName(const std::string
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendQuit()
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendQuit()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_QUIT, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_QUIT, TCP_MTU);
|
||||||
|
|
||||||
my_client->SendPacket(std::move(p));
|
my_client->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
@@ -729,7 +740,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(const std::string &pa
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendMove(CompanyID company, const std::string &password)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendMove(CompanyID company, const std::string &password)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_MOVE, TCP_MTU);
|
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_MOVE, TCP_MTU);
|
||||||
p->Send_uint8(company);
|
p->Send_uint8(company);
|
||||||
p->Send_string(GenerateCompanyPasswordHash(password, _company_password_server_id, _company_password_game_seed));
|
p->Send_string(GenerateCompanyPasswordHash(password, _company_password_server_id, _company_password_game_seed));
|
||||||
my_client->SendPacket(std::move(p));
|
my_client->SendPacket(std::move(p));
|
||||||
@@ -852,6 +863,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet &p
|
|||||||
STR_NETWORK_ERROR_TIMEOUT_MAP, // NETWORK_ERROR_TIMEOUT_MAP
|
STR_NETWORK_ERROR_TIMEOUT_MAP, // NETWORK_ERROR_TIMEOUT_MAP
|
||||||
STR_NETWORK_ERROR_TIMEOUT_JOIN, // NETWORK_ERROR_TIMEOUT_JOIN
|
STR_NETWORK_ERROR_TIMEOUT_JOIN, // NETWORK_ERROR_TIMEOUT_JOIN
|
||||||
STR_NETWORK_ERROR_INVALID_CLIENT_NAME, // NETWORK_ERROR_INVALID_CLIENT_NAME
|
STR_NETWORK_ERROR_INVALID_CLIENT_NAME, // NETWORK_ERROR_INVALID_CLIENT_NAME
|
||||||
|
STR_NETWORK_ERROR_NOT_ON_ALLOW_LIST, // NETWORK_ERROR_NOT_ON_ALLOW_LIST
|
||||||
};
|
};
|
||||||
static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
|
static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
|
||||||
|
|
||||||
@@ -875,7 +887,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet &p
|
|||||||
|
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(Packet &p)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(Packet &p)
|
||||||
{
|
{
|
||||||
if (this->status != STATUS_JOIN) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status != STATUS_ENCRYPTED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
uint grf_count = p.Recv_uint32();
|
uint grf_count = p.Recv_uint32();
|
||||||
if (grf_count > MAX_NON_STATIC_GRF_COUNT) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (grf_count > MAX_NON_STATIC_GRF_COUNT) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
@@ -907,28 +919,63 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(P
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Packet &p)
|
class ClientGamePasswordRequestHandler : public NetworkAuthenticationPasswordRequestHandler {
|
||||||
|
virtual void SendResponse() override { MyClient::SendAuthResponse(); }
|
||||||
|
virtual void AskUserForPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request) override
|
||||||
|
{
|
||||||
|
if (!_network_join.server_password.empty()) {
|
||||||
|
request->Reply(_network_join.server_password);
|
||||||
|
} else {
|
||||||
|
ShowNetworkNeedPassword(NETWORK_GAME_PASSWORD, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_AUTH_REQUEST(Packet &p)
|
||||||
{
|
{
|
||||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status != STATUS_JOIN && this->status != STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
this->status = STATUS_AUTH_GAME;
|
this->status = STATUS_AUTH_GAME;
|
||||||
|
|
||||||
static_assert(_server_x25519_pub_key.size() == 32);
|
if (this->authentication_handler == nullptr) {
|
||||||
p.Recv_binary(_server_x25519_pub_key);
|
this->authentication_handler = NetworkAuthenticationClientHandler::Create(std::make_shared<ClientGamePasswordRequestHandler>(),
|
||||||
_password_server_id = p.Recv_string(NETWORK_SERVER_ID_LENGTH);
|
_settings_client.network.client_secret_key, _settings_client.network.client_public_key);
|
||||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
|
||||||
|
|
||||||
if (!_network_join.server_password.empty()) {
|
|
||||||
return SendGamePassword(_network_join.server_password);
|
|
||||||
}
|
}
|
||||||
|
switch (this->authentication_handler->ReceiveRequest(p)) {
|
||||||
|
case NetworkAuthenticationClientHandler::READY_FOR_RESPONSE:
|
||||||
|
return SendAuthResponse();
|
||||||
|
|
||||||
ShowNetworkNeedPassword(NETWORK_GAME_PASSWORD);
|
case NetworkAuthenticationClientHandler::AWAIT_USER_INPUT:
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
case NetworkAuthenticationClientHandler::INVALID:
|
||||||
|
default:
|
||||||
|
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ENABLE_ENCRYPTION(Packet &)
|
||||||
|
{
|
||||||
|
if (this->status != STATUS_AUTH_GAME || this->authentication_handler == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
|
this->receive_encryption_handler = this->authentication_handler->CreateServerToClientEncryptionHandler();
|
||||||
|
this->send_encryption_handler = this->authentication_handler->CreateClientToServerEncryptionHandler();
|
||||||
|
this->authentication_handler = nullptr;
|
||||||
|
|
||||||
|
this->status = STATUS_ENCRYPTED;
|
||||||
|
|
||||||
|
return this->SendIdentify();
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompanyPasswordRequest : public NetworkAuthenticationPasswordRequest {
|
||||||
|
virtual void Reply(const std::string &password) override
|
||||||
|
{
|
||||||
|
MyClient::SendCompanyPassword(password);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p)
|
||||||
{
|
{
|
||||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status < STATUS_ENCRYPTED || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
this->status = STATUS_AUTH_COMPANY;
|
this->status = STATUS_AUTH_COMPANY;
|
||||||
|
|
||||||
_company_password_game_seed = p.Recv_uint32();
|
_company_password_game_seed = p.Recv_uint32();
|
||||||
@@ -939,14 +986,14 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PA
|
|||||||
return SendCompanyPassword(_network_join.company_password);
|
return SendCompanyPassword(_network_join.company_password);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowNetworkNeedPassword(NETWORK_COMPANY_PASSWORD);
|
ShowNetworkNeedPassword(NETWORK_COMPANY_PASSWORD, std::make_shared<CompanyPasswordRequest>());
|
||||||
|
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet &p)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet &p)
|
||||||
{
|
{
|
||||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status < STATUS_ENCRYPTED || this->status >= STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
this->status = STATUS_AUTHORIZED;
|
this->status = STATUS_AUTHORIZED;
|
||||||
|
|
||||||
_network_own_client_id = (ClientID)p.Recv_uint32();
|
_network_own_client_id = (ClientID)p.Recv_uint32();
|
||||||
@@ -1438,8 +1485,9 @@ const char *ClientNetworkGameSocketHandler::GetServerStatusName(ServerStatus sta
|
|||||||
static const char* _server_status_names[] {
|
static const char* _server_status_names[] {
|
||||||
"INACTIVE",
|
"INACTIVE",
|
||||||
"JOIN",
|
"JOIN",
|
||||||
"NEWGRFS_CHECK",
|
|
||||||
"AUTH_GAME",
|
"AUTH_GAME",
|
||||||
|
"ENCRYPTED",
|
||||||
|
"NEWGRFS_CHECK",
|
||||||
"AUTH_COMPANY",
|
"AUTH_COMPANY",
|
||||||
"AUTHORIZED",
|
"AUTHORIZED",
|
||||||
"MAP_WAIT",
|
"MAP_WAIT",
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
/** Class for handling the client side of the game connection. */
|
/** Class for handling the client side of the game connection. */
|
||||||
class ClientNetworkGameSocketHandler : public NetworkGameSocketHandler {
|
class ClientNetworkGameSocketHandler : public NetworkGameSocketHandler {
|
||||||
private:
|
private:
|
||||||
|
std::unique_ptr<class NetworkAuthenticationClientHandler> authentication_handler; ///< The handler for the authentication.
|
||||||
std::string connection_string; ///< Address we are connected to.
|
std::string connection_string; ///< Address we are connected to.
|
||||||
std::shared_ptr<struct PacketReader> savegame; ///< Packet reader for reading the savegame.
|
std::shared_ptr<struct PacketReader> savegame; ///< Packet reader for reading the savegame.
|
||||||
uint8_t token; ///< The token we need to send back to the server to prove we're the right client.
|
uint8_t token; ///< The token we need to send back to the server to prove we're the right client.
|
||||||
@@ -24,8 +25,9 @@ private:
|
|||||||
enum ServerStatus {
|
enum ServerStatus {
|
||||||
STATUS_INACTIVE, ///< The client is not connected nor active.
|
STATUS_INACTIVE, ///< The client is not connected nor active.
|
||||||
STATUS_JOIN, ///< We are trying to join a server.
|
STATUS_JOIN, ///< We are trying to join a server.
|
||||||
STATUS_NEWGRFS_CHECK, ///< Last action was checking NewGRFs.
|
|
||||||
STATUS_AUTH_GAME, ///< Last action was requesting game (server) password.
|
STATUS_AUTH_GAME, ///< Last action was requesting game (server) password.
|
||||||
|
STATUS_ENCRYPTED, ///< The game authentication has completed and from here on the connection to the server is encrypted.
|
||||||
|
STATUS_NEWGRFS_CHECK, ///< Last action was checking NewGRFs.
|
||||||
STATUS_AUTH_COMPANY, ///< Last action was requesting company password.
|
STATUS_AUTH_COMPANY, ///< Last action was requesting company password.
|
||||||
STATUS_AUTHORIZED, ///< The client is authorized at the server.
|
STATUS_AUTHORIZED, ///< The client is authorized at the server.
|
||||||
STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map.
|
STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map.
|
||||||
@@ -54,7 +56,8 @@ protected:
|
|||||||
NetworkRecvStatus Receive_SERVER_BANNED(Packet &p) override;
|
NetworkRecvStatus Receive_SERVER_BANNED(Packet &p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_ERROR(Packet &p) override;
|
NetworkRecvStatus Receive_SERVER_ERROR(Packet &p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p) override;
|
NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet &p) override;
|
NetworkRecvStatus Receive_SERVER_AUTH_REQUEST(Packet &p) override;
|
||||||
|
NetworkRecvStatus Receive_SERVER_ENABLE_ENCRYPTION(Packet &p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p) override;
|
NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_SETTINGS_ACCESS(Packet &p) override;
|
NetworkRecvStatus Receive_SERVER_SETTINGS_ACCESS(Packet &p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_WELCOME(Packet &p) override;
|
NetworkRecvStatus Receive_SERVER_WELCOME(Packet &p) override;
|
||||||
@@ -83,6 +86,7 @@ protected:
|
|||||||
static NetworkRecvStatus SendNewGRFsOk();
|
static NetworkRecvStatus SendNewGRFsOk();
|
||||||
static NetworkRecvStatus SendGetMap();
|
static NetworkRecvStatus SendGetMap();
|
||||||
static NetworkRecvStatus SendMapOk();
|
static NetworkRecvStatus SendMapOk();
|
||||||
|
static NetworkRecvStatus SendIdentify();
|
||||||
void CheckConnection();
|
void CheckConnection();
|
||||||
|
|
||||||
NetworkRecvStatus SendKeyPasswordPacket(PacketType packet_type, NetworkSharedSecrets &ss, const std::string &password, const std::string *payload);
|
NetworkRecvStatus SendKeyPasswordPacket(PacketType packet_type, NetworkSharedSecrets &ss, const std::string &password, const std::string *payload);
|
||||||
@@ -111,7 +115,7 @@ public:
|
|||||||
static NetworkRecvStatus SendQuit();
|
static NetworkRecvStatus SendQuit();
|
||||||
static NetworkRecvStatus SendAck();
|
static NetworkRecvStatus SendAck();
|
||||||
|
|
||||||
static NetworkRecvStatus SendGamePassword(const std::string &password);
|
static NetworkRecvStatus SendAuthResponse();
|
||||||
static NetworkRecvStatus SendCompanyPassword(const std::string &password);
|
static NetworkRecvStatus SendCompanyPassword(const std::string &password);
|
||||||
static NetworkRecvStatus SendSettingsPassword(const std::string &password);
|
static NetworkRecvStatus SendSettingsPassword(const std::string &password);
|
||||||
|
|
||||||
|
@@ -204,7 +204,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentType type)
|
|||||||
|
|
||||||
this->Connect();
|
this->Connect();
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_CONTENT_CLIENT_INFO_LIST);
|
auto p = std::make_unique<Packet>(this, PACKET_CONTENT_CLIENT_INFO_LIST);
|
||||||
p->Send_uint8 ((uint8_t)type);
|
p->Send_uint8 ((uint8_t)type);
|
||||||
p->Send_uint32(0xffffffff);
|
p->Send_uint32(0xffffffff);
|
||||||
p->Send_uint8 (2);
|
p->Send_uint8 (2);
|
||||||
@@ -239,7 +239,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(uint count, const Con
|
|||||||
* The rest of the packet can be used for the IDs. */
|
* The rest of the packet can be used for the IDs. */
|
||||||
uint p_count = std::min<uint>(count, (TCP_MTU - sizeof(PacketSize) - sizeof(uint8_t) - sizeof(uint16_t)) / sizeof(uint32_t));
|
uint p_count = std::min<uint>(count, (TCP_MTU - sizeof(PacketSize) - sizeof(uint8_t) - sizeof(uint16_t)) / sizeof(uint32_t));
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_CONTENT_CLIENT_INFO_ID, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_CONTENT_CLIENT_INFO_ID, TCP_MTU);
|
||||||
p->Send_uint16(p_count);
|
p->Send_uint16(p_count);
|
||||||
|
|
||||||
for (uint i = 0; i < p_count; i++) {
|
for (uint i = 0; i < p_count; i++) {
|
||||||
@@ -269,7 +269,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo
|
|||||||
uint offset = 0;
|
uint offset = 0;
|
||||||
|
|
||||||
while (cv->size() > offset) {
|
while (cv->size() > offset) {
|
||||||
auto p = std::make_unique<Packet>(send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID, TCP_MTU);
|
||||||
const uint to_send = std::min<uint>(static_cast<uint>(cv->size() - offset), max_per_packet);
|
const uint to_send = std::min<uint>(static_cast<uint>(cv->size() - offset), max_per_packet);
|
||||||
p->Send_uint8(static_cast<uint8_t>(to_send));
|
p->Send_uint8(static_cast<uint8_t>(to_send));
|
||||||
|
|
||||||
@@ -371,7 +371,7 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const Co
|
|||||||
* The rest of the packet can be used for the IDs. */
|
* The rest of the packet can be used for the IDs. */
|
||||||
uint p_count = std::min<uint>(count, (TCP_MTU - sizeof(PacketSize) - sizeof(uint8_t) - sizeof(uint16_t)) / sizeof(uint32_t));
|
uint p_count = std::min<uint>(count, (TCP_MTU - sizeof(PacketSize) - sizeof(uint8_t) - sizeof(uint16_t)) / sizeof(uint32_t));
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_CONTENT_CLIENT_CONTENT, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_CONTENT_CLIENT_CONTENT, TCP_MTU);
|
||||||
p->Send_uint16(p_count);
|
p->Send_uint16(p_count);
|
||||||
|
|
||||||
for (uint i = 0; i < p_count; i++) {
|
for (uint i = 0; i < p_count; i++) {
|
||||||
|
@@ -458,7 +458,7 @@ void ClientNetworkCoordinatorSocketHandler::Register()
|
|||||||
|
|
||||||
this->Connect();
|
this->Connect();
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_SERVER_REGISTER);
|
auto p = std::make_unique<Packet>(this, PACKET_COORDINATOR_SERVER_REGISTER);
|
||||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||||
p->Send_uint8(_settings_client.network.server_game_type);
|
p->Send_uint8(_settings_client.network.server_game_type);
|
||||||
p->Send_uint16(_settings_client.network.server_port);
|
p->Send_uint16(_settings_client.network.server_port);
|
||||||
@@ -480,7 +480,7 @@ void ClientNetworkCoordinatorSocketHandler::SendServerUpdate()
|
|||||||
{
|
{
|
||||||
DEBUG(net, 6, "Sending server update to Game Coordinator");
|
DEBUG(net, 6, "Sending server update to Game Coordinator");
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_SERVER_UPDATE, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_COORDINATOR_SERVER_UPDATE, TCP_MTU);
|
||||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||||
SerializeNetworkGameInfo(*p, GetCurrentNetworkServerGameInfo(), this->next_update.time_since_epoch() != std::chrono::nanoseconds::zero());
|
SerializeNetworkGameInfo(*p, GetCurrentNetworkServerGameInfo(), this->next_update.time_since_epoch() != std::chrono::nanoseconds::zero());
|
||||||
|
|
||||||
@@ -498,7 +498,7 @@ void ClientNetworkCoordinatorSocketHandler::GetListing()
|
|||||||
|
|
||||||
_network_game_list_version++;
|
_network_game_list_version++;
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_CLIENT_LISTING);
|
auto p = std::make_unique<Packet>(this, PACKET_COORDINATOR_CLIENT_LISTING);
|
||||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||||
p->Send_uint8(NETWORK_GAME_INFO_VERSION);
|
p->Send_uint8(NETWORK_GAME_INFO_VERSION);
|
||||||
p->Send_string(_openttd_revision);
|
p->Send_string(_openttd_revision);
|
||||||
@@ -530,7 +530,7 @@ void ClientNetworkCoordinatorSocketHandler::ConnectToServer(const std::string &i
|
|||||||
|
|
||||||
this->Connect();
|
this->Connect();
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_CLIENT_CONNECT);
|
auto p = std::make_unique<Packet>(this, PACKET_COORDINATOR_CLIENT_CONNECT);
|
||||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||||
p->Send_string(invite_code);
|
p->Send_string(invite_code);
|
||||||
|
|
||||||
@@ -547,7 +547,7 @@ void ClientNetworkCoordinatorSocketHandler::ConnectFailure(const std::string &to
|
|||||||
/* Connecter will destroy itself. */
|
/* Connecter will destroy itself. */
|
||||||
this->game_connecter = nullptr;
|
this->game_connecter = nullptr;
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_SERCLI_CONNECT_FAILED);
|
auto p = std::make_unique<Packet>(this, PACKET_COORDINATOR_SERCLI_CONNECT_FAILED);
|
||||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||||
p->Send_string(token);
|
p->Send_string(token);
|
||||||
p->Send_uint8(tracking_number);
|
p->Send_uint8(tracking_number);
|
||||||
@@ -578,7 +578,7 @@ void ClientNetworkCoordinatorSocketHandler::ConnectSuccess(const std::string &to
|
|||||||
} else {
|
} else {
|
||||||
/* The client informs the Game Coordinator about the success. The server
|
/* The client informs the Game Coordinator about the success. The server
|
||||||
* doesn't have to, as it is implied by the client telling. */
|
* doesn't have to, as it is implied by the client telling. */
|
||||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_CLIENT_CONNECTED);
|
auto p = std::make_unique<Packet>(this, PACKET_COORDINATOR_CLIENT_CONNECTED);
|
||||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||||
p->Send_string(token);
|
p->Send_string(token);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -606,7 +606,7 @@ void ClientNetworkCoordinatorSocketHandler::ConnectSuccess(const std::string &to
|
|||||||
*/
|
*/
|
||||||
void ClientNetworkCoordinatorSocketHandler::StunResult(const std::string &token, uint8_t family, bool result)
|
void ClientNetworkCoordinatorSocketHandler::StunResult(const std::string &token, uint8_t family, bool result)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_COORDINATOR_SERCLI_STUN_RESULT);
|
auto p = std::make_unique<Packet>(this, PACKET_COORDINATOR_SERCLI_STUN_RESULT);
|
||||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||||
p->Send_string(token);
|
p->Send_string(token);
|
||||||
p->Send_uint8(family);
|
p->Send_uint8(family);
|
||||||
|
475
src/network/network_crypto.cpp
Normal file
475
src/network/network_crypto.cpp
Normal file
@@ -0,0 +1,475 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file network_crypto.cpp Implementation of the network specific cryptography helpers. */
|
||||||
|
|
||||||
|
#include "../stdafx.h"
|
||||||
|
|
||||||
|
#include "network_crypto_internal.h"
|
||||||
|
#include "core/packet.h"
|
||||||
|
|
||||||
|
#include "../3rdparty/monocypher/monocypher.h"
|
||||||
|
#include "../core/random_func.hpp"
|
||||||
|
#include "../debug.h"
|
||||||
|
#include "../debug_fmt.h"
|
||||||
|
#include "../string_func.h"
|
||||||
|
|
||||||
|
#include "../safeguards.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call \c crypto_wipe for all the data in the given span.
|
||||||
|
* @param span The span to cryptographically wipe.
|
||||||
|
*/
|
||||||
|
static void crypto_wipe(std::span<uint8_t> span)
|
||||||
|
{
|
||||||
|
crypto_wipe(span.data(), span.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ensure the derived keys do not get leaked when we're done with it. */
|
||||||
|
X25519DerivedKeys::~X25519DerivedKeys()
|
||||||
|
{
|
||||||
|
crypto_wipe(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the key to encrypt or decrypt a message sent from the client to the server.
|
||||||
|
* @return The raw bytes of the key.
|
||||||
|
*/
|
||||||
|
std::span<const uint8_t> X25519DerivedKeys::ClientToServer() const
|
||||||
|
{
|
||||||
|
return std::span(this->keys.data(), X25519_KEY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the key to encrypt or decrypt a message sent from the server to the client.
|
||||||
|
* @return The raw bytes of the key.
|
||||||
|
*/
|
||||||
|
std::span<const uint8_t> X25519DerivedKeys::ServerToClient() const
|
||||||
|
{
|
||||||
|
return std::span(this->keys.data() + X25519_KEY_SIZE, X25519_KEY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the actual key exchange.
|
||||||
|
* @param peer_public_key The public key chosen by the other participant of the key exchange.
|
||||||
|
* @param side Whether we are the client or server; used to hash the public key of us and the peer in the right order.
|
||||||
|
* @param our_secret_key The secret key of us.
|
||||||
|
* @param our_public_key The public key of us.
|
||||||
|
* @param extra_payload Extra payload to put into the hash function to create the derived keys.
|
||||||
|
* @return True when the key exchange has succeeded, false when an illegal public key was given.
|
||||||
|
*/
|
||||||
|
bool X25519DerivedKeys::Exchange(const X25519PublicKey &peer_public_key, X25519KeyExchangeSide side,
|
||||||
|
const X25519SecretKey &our_secret_key, const X25519PublicKey &our_public_key, std::string_view extra_payload)
|
||||||
|
{
|
||||||
|
X25519Key shared_secret;
|
||||||
|
crypto_x25519(shared_secret.data(), our_secret_key.data(), peer_public_key.data());
|
||||||
|
if (std::all_of(shared_secret.begin(), shared_secret.end(), [](auto v) { return v == 0; })) {
|
||||||
|
/* A shared secret of all zeros means that the peer tried to force the shared secret to a known constant. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_blake2b_ctx ctx;
|
||||||
|
crypto_blake2b_init(&ctx, this->keys.size());
|
||||||
|
crypto_blake2b_update(&ctx, shared_secret.data(), shared_secret.size());
|
||||||
|
switch (side) {
|
||||||
|
case X25519KeyExchangeSide::SERVER:
|
||||||
|
crypto_blake2b_update(&ctx, our_public_key.data(), our_public_key.size());
|
||||||
|
crypto_blake2b_update(&ctx, peer_public_key.data(), peer_public_key.size());
|
||||||
|
break;
|
||||||
|
case X25519KeyExchangeSide::CLIENT:
|
||||||
|
crypto_blake2b_update(&ctx, peer_public_key.data(), peer_public_key.size());
|
||||||
|
crypto_blake2b_update(&ctx, our_public_key.data(), our_public_key.size());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NOT_REACHED();
|
||||||
|
}
|
||||||
|
crypto_blake2b_update(&ctx, reinterpret_cast<const uint8_t *>(extra_payload.data()), extra_payload.size());
|
||||||
|
crypto_blake2b_final(&ctx, this->keys.data());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encryption handler implementation for monocypther encryption after a X25519 key exchange.
|
||||||
|
*/
|
||||||
|
class X25519EncryptionHandler : public NetworkEncryptionHandler {
|
||||||
|
private:
|
||||||
|
crypto_aead_ctx context; ///< The actual encryption context.
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create the encryption handler.
|
||||||
|
* @param key The key used for the encryption.
|
||||||
|
* @param nonce The nonce used for the encryption.
|
||||||
|
*/
|
||||||
|
X25519EncryptionHandler(const std::span<const uint8_t> key, const X25519Nonce &nonce)
|
||||||
|
{
|
||||||
|
assert(key.size() == X25519_KEY_SIZE);
|
||||||
|
crypto_aead_init_x(&this->context, key.data(), nonce.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ensure the encryption context is wiped! */
|
||||||
|
~X25519EncryptionHandler()
|
||||||
|
{
|
||||||
|
crypto_wipe(&this->context, sizeof(this->context));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MACSize() const override
|
||||||
|
{
|
||||||
|
return X25519_MAC_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Decrypt(std::span<std::uint8_t> mac, std::span<std::uint8_t> message) override
|
||||||
|
{
|
||||||
|
return crypto_aead_read(&this->context, message.data(), mac.data(), nullptr, 0, message.data(), message.size()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Encrypt(std::span<std::uint8_t> mac, std::span<std::uint8_t> message) override
|
||||||
|
{
|
||||||
|
crypto_aead_write(&this->context, message.data(), mac.data(), nullptr, 0, message.data(), message.size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Ensure the key does not get leaked when we're done with it. */
|
||||||
|
X25519Key::~X25519Key()
|
||||||
|
{
|
||||||
|
crypto_wipe(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new secret key that's filled with random bytes.
|
||||||
|
* @return The randomly filled key.
|
||||||
|
*/
|
||||||
|
/* static */ X25519SecretKey X25519SecretKey::CreateRandom()
|
||||||
|
{
|
||||||
|
X25519SecretKey secret_key;
|
||||||
|
RandomBytesWithFallback(secret_key);
|
||||||
|
return secret_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the public key associated with this secret key.
|
||||||
|
* @return The public key.
|
||||||
|
*/
|
||||||
|
X25519PublicKey X25519SecretKey::CreatePublicKey() const
|
||||||
|
{
|
||||||
|
X25519PublicKey public_key;
|
||||||
|
crypto_x25519_public_key(public_key.data(), this->data());
|
||||||
|
return public_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new nonce that's filled with random bytes.
|
||||||
|
* @return The randomly filled nonce.
|
||||||
|
*/
|
||||||
|
/* static */ X25519Nonce X25519Nonce::CreateRandom()
|
||||||
|
{
|
||||||
|
X25519Nonce nonce;
|
||||||
|
RandomBytesWithFallback(nonce);
|
||||||
|
return nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ensure the nonce does not get leaked when we're done with it. */
|
||||||
|
X25519Nonce::~X25519Nonce()
|
||||||
|
{
|
||||||
|
crypto_wipe(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the handler, and generate the public keys accordingly.
|
||||||
|
* @param secret_key The secret key to use for this handler. Defaults to secure random data.
|
||||||
|
*/
|
||||||
|
X25519AuthenticationHandler::X25519AuthenticationHandler(const X25519SecretKey &secret_key) :
|
||||||
|
our_secret_key(secret_key), our_public_key(secret_key.CreatePublicKey()), nonce(X25519Nonce::CreateRandom())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ void X25519AuthenticationHandler::SendRequest(Packet &p)
|
||||||
|
{
|
||||||
|
p.Send_bytes(this->our_public_key);
|
||||||
|
p.Send_bytes(this->nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the key exchange data from a \c Packet that came from the server,
|
||||||
|
* @param p The packet that has been received.
|
||||||
|
* @return True when the data seems correct.
|
||||||
|
*/
|
||||||
|
bool X25519AuthenticationHandler::ReceiveRequest(Packet &p)
|
||||||
|
{
|
||||||
|
if (p.RemainingBytesToTransfer() != X25519_KEY_SIZE + X25519_NONCE_SIZE) {
|
||||||
|
Debug(net, 1, "[crypto] Received auth response of illegal size; authentication aborted.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Recv_bytes(this->peer_public_key);
|
||||||
|
p.Recv_bytes(this->nonce);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the key exchange, and when that is correct fill the \c Packet with the appropriate data.
|
||||||
|
* @param p The packet that has to be sent.
|
||||||
|
* @param derived_key_extra_payload The extra payload to pass to the key exchange.
|
||||||
|
* @return Whether the key exchange was successful or not.
|
||||||
|
*/
|
||||||
|
bool X25519AuthenticationHandler::SendResponse(Packet &p, std::string_view derived_key_extra_payload)
|
||||||
|
{
|
||||||
|
if (!this->derived_keys.Exchange(this->peer_public_key, X25519KeyExchangeSide::CLIENT,
|
||||||
|
this->our_secret_key, this->our_public_key, derived_key_extra_payload)) {
|
||||||
|
Debug(net, 0, "[crypto] Peer sent an illegal public key; authentication aborted.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
X25519KeyExchangeMessage message;
|
||||||
|
RandomBytesWithFallback(message);
|
||||||
|
X25519Mac mac;
|
||||||
|
|
||||||
|
crypto_aead_lock(message.data(), mac.data(), this->derived_keys.ClientToServer().data(), nonce.data(),
|
||||||
|
this->our_public_key.data(), this->our_public_key.size(), message.data(), message.size());
|
||||||
|
|
||||||
|
p.Send_bytes(this->our_public_key);
|
||||||
|
p.Send_bytes(mac);
|
||||||
|
p.Send_bytes(message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the public key the peer provided for the key exchange.
|
||||||
|
* @return The hexadecimal string representation of the peer's public key.
|
||||||
|
*/
|
||||||
|
std::string X25519AuthenticationHandler::GetPeerPublicKey() const
|
||||||
|
{
|
||||||
|
return FormatArrayAsHex(this->peer_public_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<NetworkEncryptionHandler> X25519AuthenticationHandler::CreateClientToServerEncryptionHandler() const
|
||||||
|
{
|
||||||
|
return std::make_unique<X25519EncryptionHandler>(this->derived_keys.ClientToServer(), this->nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<NetworkEncryptionHandler> X25519AuthenticationHandler::CreateServerToClientEncryptionHandler() const
|
||||||
|
{
|
||||||
|
return std::make_unique<X25519EncryptionHandler>(this->derived_keys.ServerToClient(), this->nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the key exchange data from a \c Packet that came from the client, and check whether the client passes the key
|
||||||
|
* exchange successfully.
|
||||||
|
* @param p The packet that has been received.
|
||||||
|
* @param derived_key_extra_payload The extra payload to pass to the key exchange.
|
||||||
|
* @return Whether the authentication was successful or not.
|
||||||
|
*/
|
||||||
|
NetworkAuthenticationServerHandler::ResponseResult X25519AuthenticationHandler::ReceiveResponse(Packet &p, std::string_view derived_key_extra_payload)
|
||||||
|
{
|
||||||
|
if (p.RemainingBytesToTransfer() != X25519_KEY_SIZE + X25519_MAC_SIZE + X25519_KEY_EXCHANGE_MESSAGE_SIZE) {
|
||||||
|
Debug(net, 1, "[crypto] Received auth response of illegal size; authentication aborted.");
|
||||||
|
return NetworkAuthenticationServerHandler::NOT_AUTHENTICATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
X25519KeyExchangeMessage message{};
|
||||||
|
X25519Mac mac;
|
||||||
|
|
||||||
|
p.Recv_bytes(this->peer_public_key);
|
||||||
|
p.Recv_bytes(mac);
|
||||||
|
p.Recv_bytes(message);
|
||||||
|
|
||||||
|
if (!this->derived_keys.Exchange(this->peer_public_key, X25519KeyExchangeSide::SERVER,
|
||||||
|
this->our_secret_key, this->our_public_key, derived_key_extra_payload)) {
|
||||||
|
Debug(net, 0, "[crypto] Peer sent an illegal public key; authentication aborted.");
|
||||||
|
return NetworkAuthenticationServerHandler::NOT_AUTHENTICATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypto_aead_unlock(message.data(), mac.data(), this->derived_keys.ClientToServer().data(), nonce.data(),
|
||||||
|
this->peer_public_key.data(), this->peer_public_key.size(), message.data(), message.size()) != 0) {
|
||||||
|
/*
|
||||||
|
* The ciphertext and the message authentication code do not match with the encryption key.
|
||||||
|
* This is most likely an invalid password, or possibly a bug in the client.
|
||||||
|
*/
|
||||||
|
return NetworkAuthenticationServerHandler::NOT_AUTHENTICATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NetworkAuthenticationServerHandler::AUTHENTICATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* virtual */ NetworkAuthenticationClientHandler::RequestResult X25519PAKEClientHandler::ReceiveRequest(struct Packet &p)
|
||||||
|
{
|
||||||
|
bool success = this->X25519AuthenticationHandler::ReceiveRequest(p);
|
||||||
|
if (!success) return NetworkAuthenticationClientHandler::INVALID;
|
||||||
|
|
||||||
|
this->handler->AskUserForPassword(this->handler);
|
||||||
|
return NetworkAuthenticationClientHandler::AWAIT_USER_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the secret key from the given string. If that is not a valid secret key, reset it with a random one.
|
||||||
|
* Furthermore update the public key so it is always in sync with the private key.
|
||||||
|
* @param secret_key The secret key to read/validate/fix.
|
||||||
|
* @param public_key The public key to update.
|
||||||
|
* @return The valid secret key.
|
||||||
|
*/
|
||||||
|
/* static */ X25519SecretKey X25519AuthorizedKeyClientHandler::GetValidSecretKeyAndUpdatePublicKey(std::string &secret_key, std::string &public_key)
|
||||||
|
{
|
||||||
|
X25519SecretKey key{};
|
||||||
|
if (!ConvertHexToBytes(secret_key, key)) {
|
||||||
|
if (secret_key.empty()) {
|
||||||
|
Debug(net, 3, "[crypto] Creating a new random key");
|
||||||
|
} else {
|
||||||
|
Debug(net, 0, "[crypto] Found invalid secret key, creating a new random key");
|
||||||
|
}
|
||||||
|
key = X25519SecretKey::CreateRandom();
|
||||||
|
secret_key = FormatArrayAsHex(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public_key = FormatArrayAsHex(key.CreatePublicKey());
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ NetworkAuthenticationServerHandler::ResponseResult X25519AuthorizedKeyServerHandler::ReceiveResponse(Packet &p)
|
||||||
|
{
|
||||||
|
ResponseResult result = this->X25519AuthenticationHandler::ReceiveResponse(p, {});
|
||||||
|
if (result != AUTHENTICATED) return result;
|
||||||
|
|
||||||
|
std::string peer_public_key = this->GetPeerPublicKey();
|
||||||
|
return this->authorized_key_handler->IsAllowed(peer_public_key) ? AUTHENTICATED : NOT_AUTHENTICATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* virtual */ NetworkAuthenticationClientHandler::RequestResult CombinedAuthenticationClientHandler::ReceiveRequest(struct Packet &p)
|
||||||
|
{
|
||||||
|
NetworkAuthenticationMethod method = static_cast<NetworkAuthenticationMethod>(p.Recv_uint8());
|
||||||
|
|
||||||
|
auto is_of_method = [method](Handler &handler) { return handler->GetAuthenticationMethod() == method; };
|
||||||
|
auto it = std::find_if(handlers.begin(), handlers.end(), is_of_method);
|
||||||
|
if (it == handlers.end()) return INVALID;
|
||||||
|
|
||||||
|
this->current_handler = it->get();
|
||||||
|
|
||||||
|
Debug(net, 9, "Received {} authentication request", this->GetName());
|
||||||
|
return this->current_handler->ReceiveRequest(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ bool CombinedAuthenticationClientHandler::SendResponse(struct Packet &p)
|
||||||
|
{
|
||||||
|
Debug(net, 9, "Sending {} authentication response", this->GetName());
|
||||||
|
|
||||||
|
return this->current_handler->SendResponse(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ std::string_view CombinedAuthenticationClientHandler::GetName() const
|
||||||
|
{
|
||||||
|
return this->current_handler != nullptr ? this->current_handler->GetName() : "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ NetworkAuthenticationMethod CombinedAuthenticationClientHandler::GetAuthenticationMethod() const
|
||||||
|
{
|
||||||
|
return this->current_handler != nullptr ? this->current_handler->GetAuthenticationMethod() : NETWORK_AUTH_METHOD_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given sub-handler to this handler, if the handler can be used (e.g. there are authorized keys or there is a password).
|
||||||
|
* @param handler The handler to add.
|
||||||
|
*/
|
||||||
|
void CombinedAuthenticationServerHandler::Add(CombinedAuthenticationServerHandler::Handler &&handler)
|
||||||
|
{
|
||||||
|
/* Is the handler configured correctly, e.g. does it have a password? */
|
||||||
|
if (!handler->CanBeUsed()) return;
|
||||||
|
|
||||||
|
this->handlers.push_back(std::move(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ void CombinedAuthenticationServerHandler::SendRequest(struct Packet &p)
|
||||||
|
{
|
||||||
|
Debug(net, 9, "Sending {} authentication request", this->GetName());
|
||||||
|
|
||||||
|
p.Send_uint8(this->handlers.back()->GetAuthenticationMethod());
|
||||||
|
this->handlers.back()->SendRequest(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ NetworkAuthenticationServerHandler::ResponseResult CombinedAuthenticationServerHandler::ReceiveResponse(struct Packet &p)
|
||||||
|
{
|
||||||
|
Debug(net, 9, "Receiving {} authentication response", this->GetName());
|
||||||
|
|
||||||
|
ResponseResult result = this->handlers.back()->ReceiveResponse(p);
|
||||||
|
if (result != NOT_AUTHENTICATED) return result;
|
||||||
|
|
||||||
|
this->handlers.pop_back();
|
||||||
|
return this->CanBeUsed() ? RETRY_NEXT_METHOD : NOT_AUTHENTICATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ std::string_view CombinedAuthenticationServerHandler::GetName() const
|
||||||
|
{
|
||||||
|
return this->CanBeUsed() ? this->handlers.back()->GetName() : "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ NetworkAuthenticationMethod CombinedAuthenticationServerHandler::GetAuthenticationMethod() const
|
||||||
|
{
|
||||||
|
return this->CanBeUsed() ? this->handlers.back()->GetAuthenticationMethod() : NETWORK_AUTH_METHOD_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ bool CombinedAuthenticationServerHandler::CanBeUsed() const
|
||||||
|
{
|
||||||
|
return !this->handlers.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* virtual */ void NetworkAuthenticationPasswordRequestHandler::Reply(const std::string &password)
|
||||||
|
{
|
||||||
|
this->password = password;
|
||||||
|
this->SendResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ bool NetworkAuthenticationDefaultAuthorizedKeyHandler::IsAllowed(std::string_view peer_public_key) const
|
||||||
|
{
|
||||||
|
for (const auto &allowed : *this->authorized_keys) {
|
||||||
|
if (StrEqualsIgnoreCase(allowed, peer_public_key)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a NetworkAuthenticationClientHandler.
|
||||||
|
* @param password_handler The handler for when a request for password needs to be passed on to the user.
|
||||||
|
* @param secret_key The location where the secret key is stored; can be overwritten when invalid.
|
||||||
|
* @param public_key The location where the public key is stored; can be overwritten when invalid.
|
||||||
|
*/
|
||||||
|
/* static */ std::unique_ptr<NetworkAuthenticationClientHandler> NetworkAuthenticationClientHandler::Create(std::shared_ptr<NetworkAuthenticationPasswordRequestHandler> password_handler, std::string &secret_key, std::string &public_key)
|
||||||
|
{
|
||||||
|
auto secret = X25519AuthorizedKeyClientHandler::GetValidSecretKeyAndUpdatePublicKey(secret_key, public_key);
|
||||||
|
auto handler = std::make_unique<CombinedAuthenticationClientHandler>();
|
||||||
|
handler->Add(std::make_unique<X25519KeyExchangeOnlyClientHandler>(secret));
|
||||||
|
handler->Add(std::make_unique<X25519PAKEClientHandler>(secret, std::move(password_handler)));
|
||||||
|
handler->Add(std::make_unique<X25519AuthorizedKeyClientHandler>(secret));
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a NetworkAuthenticationServerHandler.
|
||||||
|
* @param password_provider Callback to provide the password handling. Must remain valid until the authentication has succeeded or failed. Can be \c nullptr to skip password checks.
|
||||||
|
* @param authorized_key_handler Callback to provide the authorized key handling. Must remain valid until the authentication has succeeded or failed. Can be \c nullptr to skip authorized key checks.
|
||||||
|
* @param client_supported_method_mask Bitmask of the methods that are supported by the client. Defaults to support of all methods.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<NetworkAuthenticationServerHandler> NetworkAuthenticationServerHandler::Create(const NetworkAuthenticationPasswordProvider *password_provider, const NetworkAuthenticationAuthorizedKeyHandler *authorized_key_handler, NetworkAuthenticationMethodMask client_supported_method_mask)
|
||||||
|
{
|
||||||
|
auto secret = X25519SecretKey::CreateRandom();
|
||||||
|
auto handler = std::make_unique<CombinedAuthenticationServerHandler>();
|
||||||
|
if (password_provider != nullptr && HasBit(client_supported_method_mask, NETWORK_AUTH_METHOD_X25519_PAKE)) {
|
||||||
|
handler->Add(std::make_unique<X25519PAKEServerHandler>(secret, password_provider));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authorized_key_handler != nullptr && HasBit(client_supported_method_mask, NETWORK_AUTH_METHOD_X25519_AUTHORIZED_KEY)) {
|
||||||
|
handler->Add(std::make_unique<X25519AuthorizedKeyServerHandler>(secret, authorized_key_handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handler->CanBeUsed() && HasBit(client_supported_method_mask, NETWORK_AUTH_METHOD_X25519_KEY_EXCHANGE_ONLY)) {
|
||||||
|
/* Fall back to the plain handler when neither password, nor authorized keys are configured. */
|
||||||
|
handler->Add(std::make_unique<X25519KeyExchangeOnlyServerHandler>(secret));
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
|
}
|
287
src/network/network_crypto.h
Normal file
287
src/network/network_crypto.h
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file network_crypto.h Crypto specific bits of the network handling.
|
||||||
|
*
|
||||||
|
* This provides a set of functionality to perform authentication combined with a key exchange,
|
||||||
|
* to create a shared secret as well as encryption using those shared secrets.
|
||||||
|
*
|
||||||
|
* For the authentication/key exchange, the server determines the available methods and creates
|
||||||
|
* the appropriate \c NetworkAuthenticationServerHandler. This will be used to create a request
|
||||||
|
* for the client, which instantiates a \c NetworkAuthenticationClientHandler to handle that
|
||||||
|
* request.
|
||||||
|
* At the moment there are three types of request: key exchange only, password-authenticated key
|
||||||
|
* exchange (PAKE) and authorized keys. When the request is for a password, the user is asked
|
||||||
|
* for the password via an essentially asynchronous callback from the client handler. For the
|
||||||
|
* other requests no input from the user is needed, and these are immediately ready to generate
|
||||||
|
* the response for the server.
|
||||||
|
*
|
||||||
|
* The server will validate the response resulting in either the user being authenticated or not.
|
||||||
|
* When the user failed authentication, there might be a possibility to retry. For example when
|
||||||
|
* the server has configured authorized keys and passwords; when the client fails with the
|
||||||
|
* authorized keys, it will retry with the password.
|
||||||
|
*
|
||||||
|
* Once the key exchange/authentication has been done, the server can signal the client to
|
||||||
|
* upgrade the network connection to use encryption using the shared secret of the key exchange.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NETWORK_CRYPTO_H
|
||||||
|
#define NETWORK_CRYPTO_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for handling the encryption (or decryption) of a network connection.
|
||||||
|
*/
|
||||||
|
class NetworkEncryptionHandler {
|
||||||
|
public:
|
||||||
|
virtual ~NetworkEncryptionHandler() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of the MAC (Message Authentication Code) used by the underlying encryption protocol.
|
||||||
|
* @return The size, in bytes, of the MACs.
|
||||||
|
*/
|
||||||
|
virtual size_t MACSize() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt the given message in-place, validating against the given MAC.
|
||||||
|
* @param mac The message authentication code (MAC).
|
||||||
|
* @param message The location of the message to decrypt.
|
||||||
|
* @return Whether decryption and authentication/validation of the message succeeded.
|
||||||
|
*/
|
||||||
|
virtual bool Decrypt(std::span<std::uint8_t> mac, std::span<std::uint8_t> message) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt the given message in-place, and write the associated MAC.
|
||||||
|
* @param mac The location to write the message authentication code (MAC) to.
|
||||||
|
* @param message The location of the message to encrypt.
|
||||||
|
*/
|
||||||
|
virtual void Encrypt(std::span<std::uint8_t> mac, std::span<std::uint8_t> message) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback interface for requests for passwords in the context of network authentication.
|
||||||
|
*/
|
||||||
|
class NetworkAuthenticationPasswordRequest {
|
||||||
|
public:
|
||||||
|
virtual ~NetworkAuthenticationPasswordRequest() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reply to the request with the given password.
|
||||||
|
*/
|
||||||
|
virtual void Reply(const std::string &password) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback interface for client implementations to provide the handling of the password requests.
|
||||||
|
*/
|
||||||
|
class NetworkAuthenticationPasswordRequestHandler : public NetworkAuthenticationPasswordRequest {
|
||||||
|
protected:
|
||||||
|
friend class X25519PAKEClientHandler;
|
||||||
|
|
||||||
|
std::string password; ///< The entered password.
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void Reply(const std::string &password) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to trigger sending the response for the password request.
|
||||||
|
*/
|
||||||
|
virtual void SendResponse() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to trigger asking the user for the password.
|
||||||
|
* @param request The request to the user, to which it can reply with the password.
|
||||||
|
*/
|
||||||
|
virtual void AskUserForPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback interface for server implementations to provide the current password.
|
||||||
|
*/
|
||||||
|
class NetworkAuthenticationPasswordProvider {
|
||||||
|
public:
|
||||||
|
virtual ~NetworkAuthenticationPasswordProvider() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to return the password where to validate against.
|
||||||
|
* @return \c std::string_view of the current password; an empty view means no password check will be performed.
|
||||||
|
*/
|
||||||
|
virtual std::string_view GetPassword() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of the password provider.
|
||||||
|
*/
|
||||||
|
class NetworkAuthenticationDefaultPasswordProvider : public NetworkAuthenticationPasswordProvider {
|
||||||
|
private:
|
||||||
|
const std::string *password; ///< The password to check against.
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create the provider with the pointer to the password that is to be used. A pointer, so this can handle
|
||||||
|
* situations where the password gets changed over time.
|
||||||
|
* @param password The reference to the configured password.
|
||||||
|
*/
|
||||||
|
NetworkAuthenticationDefaultPasswordProvider(const std::string &password) : password(&password) {}
|
||||||
|
|
||||||
|
std::string_view GetPassword() const override { return *this->password; };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback interface for server implementations to provide the authorized key validation.
|
||||||
|
*/
|
||||||
|
class NetworkAuthenticationAuthorizedKeyHandler {
|
||||||
|
public:
|
||||||
|
virtual ~NetworkAuthenticationAuthorizedKeyHandler() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the key handler can be used, i.e. whether there are authorized keys to check against.
|
||||||
|
* @return \c true when it can be used, otherwise \c false.
|
||||||
|
*/
|
||||||
|
virtual bool CanBeUsed() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given public key of the peer is allowed in.
|
||||||
|
* @param peer_public_key The public key of the peer to check against.
|
||||||
|
* @return \c true when the key is allowed, otherwise \c false.
|
||||||
|
*/
|
||||||
|
virtual bool IsAllowed(std::string_view peer_public_key) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation for the authorized key handler.
|
||||||
|
*/
|
||||||
|
class NetworkAuthenticationDefaultAuthorizedKeyHandler : public NetworkAuthenticationAuthorizedKeyHandler {
|
||||||
|
private:
|
||||||
|
const std::vector<std::string> *authorized_keys; ///< The authorized keys to check against.
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create the handler that uses the given authorized keys to check against.
|
||||||
|
* @param authorized_keys The reference to the authorized keys to check against.
|
||||||
|
*/
|
||||||
|
NetworkAuthenticationDefaultAuthorizedKeyHandler(const std::vector<std::string> &authorized_keys) : authorized_keys(&authorized_keys) {}
|
||||||
|
|
||||||
|
bool CanBeUsed() const override { return !this->authorized_keys->empty(); }
|
||||||
|
bool IsAllowed(std::string_view peer_public_key) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** The authentication method that can be used. */
|
||||||
|
enum NetworkAuthenticationMethod : uint8_t {
|
||||||
|
NETWORK_AUTH_METHOD_X25519_KEY_EXCHANGE_ONLY, ///< No actual authentication is taking place, just perform a x25519 key exchange.
|
||||||
|
NETWORK_AUTH_METHOD_X25519_PAKE, ///< Authentication using x25519 password-authenticated key agreement.
|
||||||
|
NETWORK_AUTH_METHOD_X25519_AUTHORIZED_KEY, ///< Authentication using x22519 key exchange and authorized keys.
|
||||||
|
NETWORK_AUTH_METHOD_END, ///< Must ALWAYS be on the end of this list!! (period)
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The mask of authentication methods that can be used. */
|
||||||
|
using NetworkAuthenticationMethodMask = uint16_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for cryptographic authentication handlers.
|
||||||
|
*/
|
||||||
|
class NetworkAuthenticationHandler {
|
||||||
|
public:
|
||||||
|
virtual ~NetworkAuthenticationHandler() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the handler for debug messages.
|
||||||
|
* @return The name of the handler.
|
||||||
|
*/
|
||||||
|
virtual std::string_view GetName() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the method this handler is providing functionality for.
|
||||||
|
* @return The \c NetworkAuthenticationMethod.
|
||||||
|
*/
|
||||||
|
virtual NetworkAuthenticationMethod GetAuthenticationMethod() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a \a NetworkEncryptionHandler to encrypt or decrypt messages from the client to the server.
|
||||||
|
* @return The handler for the client to server encryption.
|
||||||
|
*/
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateClientToServerEncryptionHandler() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a \a NetworkEncryptionHandler to encrypt or decrypt messages from the server to the client.
|
||||||
|
* @return The handler for the server to client encryption.
|
||||||
|
*/
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateServerToClientEncryptionHandler() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for client side cryptographic authentication handlers.
|
||||||
|
*/
|
||||||
|
class NetworkAuthenticationClientHandler : public NetworkAuthenticationHandler {
|
||||||
|
public:
|
||||||
|
/** The processing result of receiving a request. */
|
||||||
|
enum RequestResult {
|
||||||
|
AWAIT_USER_INPUT, ///< We have requested some user input, but must wait on that.
|
||||||
|
READY_FOR_RESPONSE, ///< We do not have to wait for user input, and can immediately respond to the server.
|
||||||
|
INVALID, ///< We have received an invalid request.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a request from the server.
|
||||||
|
* @param p The packet to read the request from.
|
||||||
|
* @return True when valid, otherwise false.
|
||||||
|
*/
|
||||||
|
virtual RequestResult ReceiveRequest(struct Packet &p) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the response to send to the server.
|
||||||
|
* @param p The packet to write the response from.
|
||||||
|
* @return True when a valid packet was made, otherwise false.
|
||||||
|
*/
|
||||||
|
virtual bool SendResponse(struct Packet &p) = 0;
|
||||||
|
|
||||||
|
static std::unique_ptr<NetworkAuthenticationClientHandler> Create(std::shared_ptr<NetworkAuthenticationPasswordRequestHandler> password_handler, std::string &secret_key, std::string &public_key);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for server side cryptographic authentication handlers.
|
||||||
|
*/
|
||||||
|
class NetworkAuthenticationServerHandler : public NetworkAuthenticationHandler {
|
||||||
|
public:
|
||||||
|
/** The processing result of receiving a response. */
|
||||||
|
enum ResponseResult {
|
||||||
|
AUTHENTICATED, ///< The client was authenticated successfully.
|
||||||
|
NOT_AUTHENTICATED, ///< All authentications for this handler have been exhausted.
|
||||||
|
RETRY_NEXT_METHOD, ///< The client failed to authenticate, but there is another method to try.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the request to send to the client.
|
||||||
|
* @param p The packet to write the request to.
|
||||||
|
*/
|
||||||
|
virtual void SendRequest(struct Packet &p) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the response from the client.
|
||||||
|
* @param p The packet to read the response from.
|
||||||
|
* @return The \c ResponseResult describing the result.
|
||||||
|
*/
|
||||||
|
virtual ResponseResult ReceiveResponse(struct Packet &p) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether this handler can be used with the current configuration.
|
||||||
|
* For example when there is no password, the handler cannot be used.
|
||||||
|
* @return True when this handler can be used.
|
||||||
|
*/
|
||||||
|
virtual bool CanBeUsed() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the public key the peer provided during the authentication.
|
||||||
|
* @return The hexadecimal string representation of the peer's public key.
|
||||||
|
*/
|
||||||
|
virtual std::string GetPeerPublicKey() const = 0;
|
||||||
|
|
||||||
|
static std::unique_ptr<NetworkAuthenticationServerHandler> Create(const NetworkAuthenticationPasswordProvider *password_provider, const NetworkAuthenticationAuthorizedKeyHandler *authorized_key_handler, NetworkAuthenticationMethodMask client_supported_method_mask = ~static_cast<NetworkAuthenticationMethodMask>(0));
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* NETWORK_CRYPTO_H */
|
341
src/network/network_crypto_internal.h
Normal file
341
src/network/network_crypto_internal.h
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file network_crypto_internal.h Internal bits to the crypto of the network handling. */
|
||||||
|
|
||||||
|
#ifndef NETWORK_CRYPTO_INTERNAL_H
|
||||||
|
#define NETWORK_CRYPTO_INTERNAL_H
|
||||||
|
|
||||||
|
#include "network_crypto.h"
|
||||||
|
|
||||||
|
/** The number of bytes the public and secret keys are in X25519. */
|
||||||
|
constexpr size_t X25519_KEY_SIZE = 32;
|
||||||
|
/** The number of bytes the nonces are in X25519. */
|
||||||
|
constexpr size_t X25519_NONCE_SIZE = 24;
|
||||||
|
/** The number of bytes the message authentication codes are in X25519. */
|
||||||
|
constexpr size_t X25519_MAC_SIZE = 16;
|
||||||
|
/** The number of bytes the (random) payload of the authentication message has. */
|
||||||
|
constexpr size_t X25519_KEY_EXCHANGE_MESSAGE_SIZE = 8;
|
||||||
|
|
||||||
|
/** Container for a X25519 key that is automatically crypto-wiped when destructed. */
|
||||||
|
struct X25519Key : std::array<uint8_t, X25519_KEY_SIZE> {
|
||||||
|
~X25519Key();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Container for a X25519 public key. */
|
||||||
|
struct X25519PublicKey : X25519Key {
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Container for a X25519 secret key. */
|
||||||
|
struct X25519SecretKey : X25519Key {
|
||||||
|
static X25519SecretKey CreateRandom();
|
||||||
|
X25519PublicKey CreatePublicKey() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Container for a X25519 nonce that is automatically crypto-wiped when destructed. */
|
||||||
|
struct X25519Nonce : std::array<uint8_t, X25519_NONCE_SIZE> {
|
||||||
|
static X25519Nonce CreateRandom();
|
||||||
|
~X25519Nonce();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Container for a X25519 message authentication code. */
|
||||||
|
using X25519Mac = std::array<uint8_t, X25519_MAC_SIZE>;
|
||||||
|
|
||||||
|
/** Container for a X25519 key exchange message. */
|
||||||
|
using X25519KeyExchangeMessage = std::array<uint8_t, X25519_KEY_EXCHANGE_MESSAGE_SIZE>;
|
||||||
|
|
||||||
|
/** The side of the key exchange. */
|
||||||
|
enum class X25519KeyExchangeSide {
|
||||||
|
CLIENT, ///< We are the client.
|
||||||
|
SERVER, ///< We are the server.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container for the keys that derived from the X25519 key exchange mechanism. This mechanism derives
|
||||||
|
* a key to encrypt both the client-to-server and a key to encrypt server-to-client communication.
|
||||||
|
*/
|
||||||
|
class X25519DerivedKeys {
|
||||||
|
private:
|
||||||
|
/** Single contiguous buffer to store the derived keys in, as they are generated as a single hash. */
|
||||||
|
std::array<uint8_t, X25519_KEY_SIZE + X25519_KEY_SIZE> keys;
|
||||||
|
public:
|
||||||
|
~X25519DerivedKeys();
|
||||||
|
std::span<const uint8_t> ClientToServer() const;
|
||||||
|
std::span<const uint8_t> ServerToClient() const;
|
||||||
|
bool Exchange(const X25519PublicKey &peer_public_key, X25519KeyExchangeSide side,
|
||||||
|
const X25519SecretKey &our_secret_key, const X25519PublicKey &our_public_key, std::string_view extra_payload);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base for handlers using a X25519 key exchange to perform authentication.
|
||||||
|
*
|
||||||
|
* In general this works as follows:
|
||||||
|
* 1) the client and server have or generate a secret and public X25519 key.
|
||||||
|
* 2) the X25519 key exchange is performed at both the client and server, with their own secret key and their peer's public key.
|
||||||
|
* 3) a pair of derived keys is created by BLAKE2b-hashing the following into 64 bytes, in this particular order:
|
||||||
|
* - the shared secret from the key exchange;
|
||||||
|
* - the public key of the server;
|
||||||
|
* - the public key of the client;
|
||||||
|
* - optional extra payload, e.g. a password in the case of PAKE.
|
||||||
|
* The first of the pair of derived keys is usually used to encrypt client-to-server communication, and the second of the pair
|
||||||
|
* is usually used to encrypt server-to-client communication.
|
||||||
|
* 4) a XChaCha20-Poly1305 (authenticated) encryption is performed using:
|
||||||
|
* - the first of the pair of derived keys as encryption key;
|
||||||
|
* - a 24 byte nonce;
|
||||||
|
* - the public key of the client as additional authenticated data.
|
||||||
|
* - a 8 byte random number as content/message.
|
||||||
|
*
|
||||||
|
* The server initiates the request by sending its public key and a 24 byte nonce that is randomly generated. Normally the side
|
||||||
|
* that sends the encrypted data sends the nonce in their packet, which would be the client on our case. However, there are
|
||||||
|
* many implementations of clients due to the admin-protocol where this is used, and we cannot guarantee that they generate a
|
||||||
|
* good enough nonce. As such the server sends one instead. The server will create a new set of keys for each session.
|
||||||
|
*
|
||||||
|
* The client receives the request, performs the key exchange, generates the derived keys and then encrypts the message. This
|
||||||
|
* message must contain some content, so it has to be filled with 8 random bytes. Once the message has been encrypted, the
|
||||||
|
* client sends their public key, the encrypted message and the message authentication code (MAC) to the server in a response.
|
||||||
|
*
|
||||||
|
* The server receives the response, performs the key exchange, generates the derived keys, decrypts the message and validates the
|
||||||
|
* message authentication code, and finally the message. It is up to the sub class to perform the final authentication checks.
|
||||||
|
*/
|
||||||
|
class X25519AuthenticationHandler {
|
||||||
|
private:
|
||||||
|
X25519SecretKey our_secret_key; ///< The secret key used by us.
|
||||||
|
X25519PublicKey our_public_key; ///< The public key used by us.
|
||||||
|
X25519Nonce nonce; ///< The nonce to prevent replay attacks.
|
||||||
|
X25519DerivedKeys derived_keys; ///< Keys derived from the authentication process.
|
||||||
|
X25519PublicKey peer_public_key; ///< The public key used by our peer.
|
||||||
|
|
||||||
|
protected:
|
||||||
|
X25519AuthenticationHandler(const X25519SecretKey &secret_key);
|
||||||
|
|
||||||
|
void SendRequest(struct Packet &p);
|
||||||
|
bool ReceiveRequest(struct Packet &p);
|
||||||
|
bool SendResponse(struct Packet &p, std::string_view derived_key_extra_payload);
|
||||||
|
NetworkAuthenticationServerHandler::ResponseResult ReceiveResponse(struct Packet &p, std::string_view derived_key_extra_payload);
|
||||||
|
|
||||||
|
std::string GetPeerPublicKey() const;
|
||||||
|
|
||||||
|
std::unique_ptr<NetworkEncryptionHandler> CreateClientToServerEncryptionHandler() const;
|
||||||
|
std::unique_ptr<NetworkEncryptionHandler> CreateServerToClientEncryptionHandler() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client side handler for using X25519 without actual authentication.
|
||||||
|
*
|
||||||
|
* This follows the method described in \c X25519AuthenticationHandler, without an extra payload.
|
||||||
|
*/
|
||||||
|
class X25519KeyExchangeOnlyClientHandler : protected X25519AuthenticationHandler, public NetworkAuthenticationClientHandler {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create the handler that that one does the key exchange.
|
||||||
|
* @param secret_key The secret key to initialize this handler with.
|
||||||
|
*/
|
||||||
|
X25519KeyExchangeOnlyClientHandler(const X25519SecretKey &secret_key) : X25519AuthenticationHandler(secret_key) {}
|
||||||
|
|
||||||
|
virtual RequestResult ReceiveRequest(struct Packet &p) override { return this->X25519AuthenticationHandler::ReceiveRequest(p) ? READY_FOR_RESPONSE : INVALID; }
|
||||||
|
virtual bool SendResponse(struct Packet &p) override { return this->X25519AuthenticationHandler::SendResponse(p, {}); }
|
||||||
|
|
||||||
|
virtual std::string_view GetName() const override { return "X25519-KeyExchangeOnly-client"; }
|
||||||
|
virtual NetworkAuthenticationMethod GetAuthenticationMethod() const override { return NETWORK_AUTH_METHOD_X25519_KEY_EXCHANGE_ONLY; }
|
||||||
|
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateClientToServerEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateClientToServerEncryptionHandler(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateServerToClientEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateServerToClientEncryptionHandler(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server side handler for using X25519 without actual authentication.
|
||||||
|
*
|
||||||
|
* This follows the method described in \c X25519AuthenticationHandler, without an extra payload.
|
||||||
|
*/
|
||||||
|
class X25519KeyExchangeOnlyServerHandler : protected X25519AuthenticationHandler, public NetworkAuthenticationServerHandler {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create the handler that that one does the key exchange.
|
||||||
|
* @param secret_key The secret key to initialize this handler with.
|
||||||
|
*/
|
||||||
|
X25519KeyExchangeOnlyServerHandler(const X25519SecretKey &secret_key) : X25519AuthenticationHandler(secret_key) {}
|
||||||
|
|
||||||
|
virtual void SendRequest(struct Packet &p) override { this->X25519AuthenticationHandler::SendRequest(p); }
|
||||||
|
virtual ResponseResult ReceiveResponse(struct Packet &p) override { return this->X25519AuthenticationHandler::ReceiveResponse(p, {}); }
|
||||||
|
|
||||||
|
virtual std::string_view GetName() const override { return "X25519-KeyExchangeOnly-server"; }
|
||||||
|
virtual NetworkAuthenticationMethod GetAuthenticationMethod() const override { return NETWORK_AUTH_METHOD_X25519_KEY_EXCHANGE_ONLY; }
|
||||||
|
virtual bool CanBeUsed() const override { return true; }
|
||||||
|
|
||||||
|
virtual std::string GetPeerPublicKey() const override { return this->X25519AuthenticationHandler::GetPeerPublicKey(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateClientToServerEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateClientToServerEncryptionHandler(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateServerToClientEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateServerToClientEncryptionHandler(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client side handler for using X25519 with a password-authenticated key exchange.
|
||||||
|
*
|
||||||
|
* This follows the method described in \c X25519AuthenticationHandler, were the password is the extra payload.
|
||||||
|
*/
|
||||||
|
class X25519PAKEClientHandler : protected X25519AuthenticationHandler, public NetworkAuthenticationClientHandler {
|
||||||
|
private:
|
||||||
|
std::shared_ptr<NetworkAuthenticationPasswordRequestHandler> handler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create the handler with the given password handler.
|
||||||
|
* @param secret_key The secret key to initialize this handler with.
|
||||||
|
* @param handler The handler requesting the password from the user, if required.
|
||||||
|
*/
|
||||||
|
X25519PAKEClientHandler(const X25519SecretKey &secret_key, std::shared_ptr<NetworkAuthenticationPasswordRequestHandler> handler) : X25519AuthenticationHandler(secret_key), handler(handler) {}
|
||||||
|
|
||||||
|
virtual RequestResult ReceiveRequest(struct Packet &p) override;
|
||||||
|
virtual bool SendResponse(struct Packet &p) override { return this->X25519AuthenticationHandler::SendResponse(p, this->handler->password); }
|
||||||
|
|
||||||
|
virtual std::string_view GetName() const override { return "X25519-PAKE-client"; }
|
||||||
|
virtual NetworkAuthenticationMethod GetAuthenticationMethod() const override { return NETWORK_AUTH_METHOD_X25519_PAKE; }
|
||||||
|
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateClientToServerEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateClientToServerEncryptionHandler(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateServerToClientEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateServerToClientEncryptionHandler(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server side handler for using X25519 with a password-authenticated key exchange.
|
||||||
|
*
|
||||||
|
* This follows the method described in \c X25519AuthenticationHandler, were the password is the extra payload.
|
||||||
|
*/
|
||||||
|
class X25519PAKEServerHandler : protected X25519AuthenticationHandler, public NetworkAuthenticationServerHandler {
|
||||||
|
private:
|
||||||
|
const NetworkAuthenticationPasswordProvider *password_provider; ///< The password to check against.
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create the handler with the given password provider.
|
||||||
|
* @param secret_key The secret key to initialize this handler with.
|
||||||
|
* @param password_provider The provider for the passwords.
|
||||||
|
*/
|
||||||
|
X25519PAKEServerHandler(const X25519SecretKey &secret_key, const NetworkAuthenticationPasswordProvider *password_provider) : X25519AuthenticationHandler(secret_key), password_provider(password_provider) {}
|
||||||
|
|
||||||
|
virtual void SendRequest(struct Packet &p) override { this->X25519AuthenticationHandler::SendRequest(p); }
|
||||||
|
virtual ResponseResult ReceiveResponse(struct Packet &p) override { return this->X25519AuthenticationHandler::ReceiveResponse(p, this->password_provider->GetPassword()); }
|
||||||
|
|
||||||
|
virtual std::string_view GetName() const override { return "X25519-PAKE-server"; }
|
||||||
|
virtual NetworkAuthenticationMethod GetAuthenticationMethod() const override { return NETWORK_AUTH_METHOD_X25519_PAKE; }
|
||||||
|
virtual bool CanBeUsed() const override { return !this->password_provider->GetPassword().empty(); }
|
||||||
|
|
||||||
|
virtual std::string GetPeerPublicKey() const override { return this->X25519AuthenticationHandler::GetPeerPublicKey(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateClientToServerEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateClientToServerEncryptionHandler(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateServerToClientEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateServerToClientEncryptionHandler(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for clients using a X25519 key exchange to perform authentication via a set of authorized (public) keys of clients.
|
||||||
|
*
|
||||||
|
* This follows the method described in \c X25519AuthenticationHandler. Once all these checks have succeeded, it will
|
||||||
|
* check whether the public key of the client is in the list of authorized keys to login.
|
||||||
|
*/
|
||||||
|
class X25519AuthorizedKeyClientHandler : protected X25519AuthenticationHandler, public NetworkAuthenticationClientHandler {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create the handler that uses the given password to check against.
|
||||||
|
* @param secret_key The secret key to initialize this handler with.
|
||||||
|
*/
|
||||||
|
X25519AuthorizedKeyClientHandler(const X25519SecretKey &secret_key) : X25519AuthenticationHandler(secret_key) {}
|
||||||
|
|
||||||
|
virtual RequestResult ReceiveRequest(struct Packet &p) override { return this->X25519AuthenticationHandler::ReceiveRequest(p) ? READY_FOR_RESPONSE : INVALID; }
|
||||||
|
virtual bool SendResponse(struct Packet &p) override { return this->X25519AuthenticationHandler::SendResponse(p, {}); }
|
||||||
|
|
||||||
|
virtual std::string_view GetName() const override { return "X25519-AuthorizedKey-client"; }
|
||||||
|
virtual NetworkAuthenticationMethod GetAuthenticationMethod() const override { return NETWORK_AUTH_METHOD_X25519_AUTHORIZED_KEY; }
|
||||||
|
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateClientToServerEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateClientToServerEncryptionHandler(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateServerToClientEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateServerToClientEncryptionHandler(); }
|
||||||
|
|
||||||
|
static X25519SecretKey GetValidSecretKeyAndUpdatePublicKey(std::string &secret_key, std::string &public_key);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for servers using a X25519 key exchange to perform authentication via a set of authorized (public) keys of clients.
|
||||||
|
*
|
||||||
|
* This follows the method described in \c X25519AuthenticationHandler. Once all these checks have succeeded, it will
|
||||||
|
* check whether the public key of the client is in the list of authorized keys to login.
|
||||||
|
*/
|
||||||
|
class X25519AuthorizedKeyServerHandler : protected X25519AuthenticationHandler, public NetworkAuthenticationServerHandler {
|
||||||
|
private:
|
||||||
|
const NetworkAuthenticationAuthorizedKeyHandler *authorized_key_handler; ///< The handler of the authorized keys.
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create the handler that uses the given authorized keys to check against.
|
||||||
|
* @param secret_key The secret key to initialize this handler with.
|
||||||
|
* @param authorized_key_handler The handler of the authorized keys.
|
||||||
|
*/
|
||||||
|
X25519AuthorizedKeyServerHandler(const X25519SecretKey &secret_key, const NetworkAuthenticationAuthorizedKeyHandler *authorized_key_handler) : X25519AuthenticationHandler(secret_key), authorized_key_handler(authorized_key_handler) {}
|
||||||
|
|
||||||
|
virtual void SendRequest(struct Packet &p) override { this->X25519AuthenticationHandler::SendRequest(p); }
|
||||||
|
virtual ResponseResult ReceiveResponse(struct Packet &p) override;
|
||||||
|
|
||||||
|
virtual std::string_view GetName() const override { return "X25519-AuthorizedKey-server"; }
|
||||||
|
virtual NetworkAuthenticationMethod GetAuthenticationMethod() const override { return NETWORK_AUTH_METHOD_X25519_AUTHORIZED_KEY; }
|
||||||
|
virtual bool CanBeUsed() const override { return this->authorized_key_handler->CanBeUsed(); }
|
||||||
|
|
||||||
|
virtual std::string GetPeerPublicKey() const override { return this->X25519AuthenticationHandler::GetPeerPublicKey(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateClientToServerEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateClientToServerEncryptionHandler(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateServerToClientEncryptionHandler() const override { return this->X25519AuthenticationHandler::CreateServerToClientEncryptionHandler(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for combining a number of authentication handlers, where the failure of one of the handlers will retry with
|
||||||
|
* another handler. For example when authorized keys fail, it can still fall back to a password.
|
||||||
|
*/
|
||||||
|
class CombinedAuthenticationClientHandler : public NetworkAuthenticationClientHandler {
|
||||||
|
public:
|
||||||
|
using Handler = std::unique_ptr<NetworkAuthenticationClientHandler>; ///< The type of the inner handlers.
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Handler> handlers; ///< The handlers that we can authenticate with.
|
||||||
|
NetworkAuthenticationClientHandler *current_handler = nullptr; ///< The currently active handler.
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Add the given sub-handler to this handler.
|
||||||
|
* @param handler The handler to add.
|
||||||
|
*/
|
||||||
|
void Add(Handler &&handler) { this->handlers.push_back(std::move(handler)); }
|
||||||
|
|
||||||
|
virtual RequestResult ReceiveRequest(struct Packet &p) override;
|
||||||
|
virtual bool SendResponse(struct Packet &p) override;
|
||||||
|
|
||||||
|
virtual std::string_view GetName() const override;
|
||||||
|
virtual NetworkAuthenticationMethod GetAuthenticationMethod() const override;
|
||||||
|
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateClientToServerEncryptionHandler() const override { return this->current_handler->CreateClientToServerEncryptionHandler(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateServerToClientEncryptionHandler() const override { return this->current_handler->CreateServerToClientEncryptionHandler(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for combining a number of authentication handlers, where the failure of one of the handlers will retry with
|
||||||
|
* another handler. For example when authorized keys fail, it can still fall back to a password.
|
||||||
|
*/
|
||||||
|
class CombinedAuthenticationServerHandler : public NetworkAuthenticationServerHandler {
|
||||||
|
public:
|
||||||
|
using Handler = std::unique_ptr<NetworkAuthenticationServerHandler>; ///< The type of the inner handlers.
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Handler> handlers; ///< The handlers that we can (still) authenticate with.
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Add(Handler &&handler);
|
||||||
|
|
||||||
|
virtual void SendRequest(struct Packet &p) override;
|
||||||
|
virtual ResponseResult ReceiveResponse(struct Packet &p) override;
|
||||||
|
|
||||||
|
virtual std::string_view GetName() const override;
|
||||||
|
virtual NetworkAuthenticationMethod GetAuthenticationMethod() const override;
|
||||||
|
virtual bool CanBeUsed() const override;
|
||||||
|
|
||||||
|
virtual std::string GetPeerPublicKey() const override { return this->handlers.back()->GetPeerPublicKey(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateClientToServerEncryptionHandler() const override { return this->handlers.back()->CreateClientToServerEncryptionHandler(); }
|
||||||
|
virtual std::unique_ptr<NetworkEncryptionHandler> CreateServerToClientEncryptionHandler() const override { return this->handlers.back()->CreateServerToClientEncryptionHandler(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* NETWORK_CRYPTO_INTERNAL_H */
|
@@ -67,6 +67,7 @@ bool NetworkCompanyIsPassworded(CompanyID company_id);
|
|||||||
uint NetworkMaxCompaniesAllowed();
|
uint NetworkMaxCompaniesAllowed();
|
||||||
bool NetworkMaxCompaniesReached();
|
bool NetworkMaxCompaniesReached();
|
||||||
void NetworkPrintClients();
|
void NetworkPrintClients();
|
||||||
|
std::string_view NetworkGetPublicKeyOfClient(ClientID client_id);
|
||||||
void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode);
|
void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode);
|
||||||
|
|
||||||
/*** Commands ran by the server ***/
|
/*** Commands ran by the server ***/
|
||||||
|
@@ -2114,7 +2114,7 @@ uint32_t _network_join_bytes; ///< The number of bytes we already down
|
|||||||
uint32_t _network_join_bytes_total; ///< The total number of bytes to download.
|
uint32_t _network_join_bytes_total; ///< The total number of bytes to download.
|
||||||
|
|
||||||
struct NetworkJoinStatusWindow : Window {
|
struct NetworkJoinStatusWindow : Window {
|
||||||
NetworkPasswordType password_type;
|
std::shared_ptr<NetworkAuthenticationPasswordRequest> request;
|
||||||
|
|
||||||
NetworkJoinStatusWindow(WindowDesc *desc) : Window(desc)
|
NetworkJoinStatusWindow(WindowDesc *desc) : Window(desc)
|
||||||
{
|
{
|
||||||
@@ -2210,16 +2210,12 @@ struct NetworkJoinStatusWindow : Window {
|
|||||||
|
|
||||||
void OnQueryTextFinished(char *str) override
|
void OnQueryTextFinished(char *str) override
|
||||||
{
|
{
|
||||||
if (StrEmpty(str)) {
|
if (StrEmpty(str) || this->request == nullptr) {
|
||||||
NetworkDisconnect();
|
NetworkDisconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (this->password_type) {
|
this->request->Reply(str);
|
||||||
case NETWORK_GAME_PASSWORD: MyClient::SendGamePassword (str); break;
|
|
||||||
case NETWORK_COMPANY_PASSWORD: MyClient::SendCompanyPassword(str); break;
|
|
||||||
default: NOT_REACHED();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2247,11 +2243,11 @@ void ShowJoinStatusWindow()
|
|||||||
new NetworkJoinStatusWindow(&_network_join_status_window_desc);
|
new NetworkJoinStatusWindow(&_network_join_status_window_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowNetworkNeedPassword(NetworkPasswordType npt)
|
void ShowNetworkNeedPassword(NetworkPasswordType npt, std::shared_ptr<NetworkAuthenticationPasswordRequest> request)
|
||||||
{
|
{
|
||||||
NetworkJoinStatusWindow *w = (NetworkJoinStatusWindow *)FindWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
NetworkJoinStatusWindow *w = (NetworkJoinStatusWindow *)FindWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||||
if (w == nullptr) return;
|
if (w == nullptr) return;
|
||||||
w->password_type = npt;
|
w->request = request;
|
||||||
|
|
||||||
StringID caption;
|
StringID caption;
|
||||||
switch (npt) {
|
switch (npt) {
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
#include "network_type.h"
|
#include "network_type.h"
|
||||||
#include "network_gamelist.h"
|
#include "network_gamelist.h"
|
||||||
|
|
||||||
void ShowNetworkNeedPassword(NetworkPasswordType npt);
|
void ShowNetworkNeedPassword(NetworkPasswordType npt, std::shared_ptr<class NetworkAuthenticationPasswordRequest> request);
|
||||||
void ShowNetworkGiveMoneyWindow(CompanyID company);
|
void ShowNetworkGiveMoneyWindow(CompanyID company);
|
||||||
void ShowNetworkChatQueryWindow(DestType type, int dest);
|
void ShowNetworkChatQueryWindow(DestType type, int dest);
|
||||||
void ShowJoinStatusWindow();
|
void ShowJoinStatusWindow();
|
||||||
|
@@ -82,7 +82,7 @@ void QueryNetworkGameSocketHandler::Send()
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus QueryNetworkGameSocketHandler::SendGameInfo()
|
NetworkRecvStatus QueryNetworkGameSocketHandler::SendGameInfo()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_CLIENT_GAME_INFO);
|
auto p = std::make_unique<Packet>(this, PACKET_CLIENT_GAME_INFO);
|
||||||
p->Send_uint32(FIND_SERVER_EXTENDED_TOKEN);
|
p->Send_uint32(FIND_SERVER_EXTENDED_TOKEN);
|
||||||
p->Send_uint8(PACKET_SERVER_GAME_INFO_EXTENDED); // reply type
|
p->Send_uint8(PACKET_SERVER_GAME_INFO_EXTENDED); // reply type
|
||||||
p->Send_uint16(0); // flags
|
p->Send_uint16(0); // flags
|
||||||
|
@@ -58,6 +58,11 @@ INSTANTIATE_POOL_METHODS(NetworkClientSocket)
|
|||||||
/** Instantiate the listen sockets. */
|
/** Instantiate the listen sockets. */
|
||||||
template SocketList TCPListenHandler<ServerNetworkGameSocketHandler, PACKET_SERVER_FULL, PACKET_SERVER_BANNED>::sockets;
|
template SocketList TCPListenHandler<ServerNetworkGameSocketHandler, PACKET_SERVER_FULL, PACKET_SERVER_BANNED>::sockets;
|
||||||
|
|
||||||
|
static NetworkAuthenticationDefaultPasswordProvider _password_provider(_settings_client.network.server_password); ///< Provides the password validation for the game's password.
|
||||||
|
static NetworkAuthenticationDefaultAuthorizedKeyHandler _authorized_key_handler(_settings_client.network.server_authorized_keys); ///< Provides the authorized key handling for the game authentication.
|
||||||
|
static NetworkAuthenticationDefaultAuthorizedKeyHandler _rcon_authorized_key_handler(_settings_client.network.rcon_authorized_keys); ///< Provides the authorized key validation for rcon.
|
||||||
|
|
||||||
|
|
||||||
/** Writing a savegame directly to a number of packets. */
|
/** Writing a savegame directly to a number of packets. */
|
||||||
struct PacketWriter : SaveFilter {
|
struct PacketWriter : SaveFilter {
|
||||||
ServerNetworkGameSocketHandler *cs; ///< Socket we are associated with.
|
ServerNetworkGameSocketHandler *cs; ///< Socket we are associated with.
|
||||||
@@ -146,7 +151,7 @@ struct PacketWriter : SaveFilter {
|
|||||||
/* We want to abort the saving when the socket is closed. */
|
/* We want to abort the saving when the socket is closed. */
|
||||||
if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
|
if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
|
||||||
|
|
||||||
if (this->current == nullptr) this->current = std::make_unique<Packet>(PACKET_SERVER_MAP_DATA, TCP_MTU);
|
if (this->current == nullptr) this->current = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DATA, TCP_MTU);
|
||||||
|
|
||||||
uint8_t *bufe = buf + size;
|
uint8_t *bufe = buf + size;
|
||||||
while (buf != bufe) {
|
while (buf != bufe) {
|
||||||
@@ -155,7 +160,7 @@ struct PacketWriter : SaveFilter {
|
|||||||
|
|
||||||
if (!this->current->CanWriteToPacket(1)) {
|
if (!this->current->CanWriteToPacket(1)) {
|
||||||
this->packets.push_back(std::move(this->current));
|
this->packets.push_back(std::move(this->current));
|
||||||
if (buf != bufe) this->current = std::make_unique<Packet>(PACKET_SERVER_MAP_DATA, TCP_MTU);
|
if (buf != bufe) this->current = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DATA, TCP_MTU);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,10 +178,10 @@ struct PacketWriter : SaveFilter {
|
|||||||
if (this->current != nullptr) this->packets.push_back(std::move(this->current));
|
if (this->current != nullptr) this->packets.push_back(std::move(this->current));
|
||||||
|
|
||||||
/* Add a packet stating that this is the end to the queue. */
|
/* Add a packet stating that this is the end to the queue. */
|
||||||
this->packets.push_back(std::make_unique<Packet>(PACKET_SERVER_MAP_DONE));
|
this->packets.push_back(std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DONE));
|
||||||
|
|
||||||
/* Fast-track the size to the client. */
|
/* Fast-track the size to the client. */
|
||||||
this->map_size_packet.reset(new Packet(PACKET_SERVER_MAP_SIZE, TCP_MTU));
|
this->map_size_packet.reset(new Packet(this->cs, PACKET_SERVER_MAP_SIZE, TCP_MTU));
|
||||||
this->map_size_packet->Send_uint32((uint32_t)this->total_size);
|
this->map_size_packet->Send_uint32((uint32_t)this->total_size);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -390,7 +395,7 @@ static void NetworkHandleCommandQueue(NetworkClientSocket *cs);
|
|||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientInfo *ci)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientInfo *ci)
|
||||||
{
|
{
|
||||||
if (ci->client_id != INVALID_CLIENT_ID) {
|
if (ci->client_id != INVALID_CLIENT_ID) {
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_CLIENT_INFO, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_CLIENT_INFO, TCP_MTU);
|
||||||
p->Send_uint32(ci->client_id);
|
p->Send_uint32(ci->client_id);
|
||||||
p->Send_uint8 (ci->client_playas);
|
p->Send_uint8 (ci->client_playas);
|
||||||
p->Send_string(ci->client_name);
|
p->Send_string(ci->client_name);
|
||||||
@@ -403,7 +408,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientIn
|
|||||||
/** Send the client information about the server. */
|
/** Send the client information about the server. */
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_GAME_INFO, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_GAME_INFO, TCP_MTU);
|
||||||
SerializeNetworkGameInfo(*p, GetCurrentNetworkServerGameInfo());
|
SerializeNetworkGameInfo(*p, GetCurrentNetworkServerGameInfo());
|
||||||
|
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -413,7 +418,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo()
|
|||||||
|
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfoExtended(PacketGameType reply_type, uint16_t flags, uint16_t version)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfoExtended(PacketGameType reply_type, uint16_t flags, uint16_t version)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(reply_type, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, reply_type, TCP_MTU);
|
||||||
SerializeNetworkGameInfoExtended(*p, GetCurrentNetworkServerGameInfo(), flags, version);
|
SerializeNetworkGameInfoExtended(*p, GetCurrentNetworkServerGameInfo(), flags, version);
|
||||||
|
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -428,7 +433,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfoExtended(PacketGam
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode error, const std::string &reason)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode error, const std::string &reason)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_ERROR, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_ERROR, TCP_MTU);
|
||||||
|
|
||||||
p->Send_uint8(error);
|
p->Send_uint8(error);
|
||||||
if (!reason.empty()) p->Send_string(reason);
|
if (!reason.empty()) p->Send_string(reason);
|
||||||
@@ -473,7 +478,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode err
|
|||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendDesyncLog(const std::string &log)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendDesyncLog(const std::string &log)
|
||||||
{
|
{
|
||||||
for (size_t offset = 0; offset < log.size();) {
|
for (size_t offset = 0; offset < log.size();) {
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_DESYNC_LOG, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_DESYNC_LOG, TCP_MTU);
|
||||||
size_t size = std::min<size_t>(log.size() - offset, TCP_MTU - 2 - p->Size());
|
size_t size = std::min<size_t>(log.size() - offset, TCP_MTU - 2 - p->Size());
|
||||||
p->Send_uint16(static_cast<uint16_t>(size));
|
p->Send_uint16(static_cast<uint16_t>(size));
|
||||||
p->Send_binary((const uint8_t *)(log.data() + offset), size);
|
p->Send_binary((const uint8_t *)(log.data() + offset), size);
|
||||||
@@ -487,18 +492,17 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendDesyncLog(const std::strin
|
|||||||
/** Send the check for the NewGRFs. */
|
/** Send the check for the NewGRFs. */
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_CHECK_NEWGRFS, TCP_MTU);
|
/* Invalid packet when status is anything but STATUS_IDENTIFY. */
|
||||||
|
if (this->status != STATUS_IDENTIFY) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||||
/* Invalid packet when status is anything but STATUS_INACTIVE. */
|
|
||||||
if (this->status != STATUS_INACTIVE) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
|
||||||
|
|
||||||
this->status = STATUS_NEWGRFS_CHECK;
|
this->status = STATUS_NEWGRFS_CHECK;
|
||||||
|
|
||||||
if (_grfconfig == nullptr) {
|
if (_grfconfig == nullptr) {
|
||||||
/* There are no NewGRFs, continue with the game password. */
|
/* There are no NewGRFs, continue with the company password. */
|
||||||
return this->SendNeedGamePassword();
|
return this->SendNeedCompanyPassword();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHECK_NEWGRFS, TCP_MTU);
|
||||||
p->Send_uint32(GetGRFConfigListNonStaticCount(_grfconfig));
|
p->Send_uint32(GetGRFConfigListNonStaticCount(_grfconfig));
|
||||||
for (const GRFConfig *c = _grfconfig; c != nullptr; c = c->next) {
|
for (const GRFConfig *c = _grfconfig; c != nullptr; c = c->next) {
|
||||||
if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(*p, c->ident);
|
if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(*p, c->ident);
|
||||||
@@ -509,27 +513,34 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Request the game password. */
|
/** Request the game password. */
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendAuthRequest()
|
||||||
{
|
{
|
||||||
/* Invalid packet when status is anything but STATUS_NEWGRFS_CHECK. */
|
/* Invalid packet when status is anything but STATUS_INACTIVE or STATUS_AUTH_GAME. */
|
||||||
if (this->status != STATUS_NEWGRFS_CHECK) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
if (this->status != STATUS_INACTIVE && status != STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||||
|
|
||||||
this->status = STATUS_AUTH_GAME;
|
this->status = STATUS_AUTH_GAME;
|
||||||
|
|
||||||
if (_settings_client.network.server_password.empty()) {
|
|
||||||
/* Do not actually need a game password, continue with the company password. */
|
|
||||||
return this->SendNeedCompanyPassword();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset 'lag' counters */
|
/* Reset 'lag' counters */
|
||||||
this->last_frame = this->last_frame_server = _frame_counter;
|
this->last_frame = this->last_frame_server = _frame_counter;
|
||||||
|
|
||||||
const NetworkGameKeys &keys = this->GetKeys();
|
if (this->authentication_handler == nullptr) {
|
||||||
|
this->authentication_handler = NetworkAuthenticationServerHandler::Create(&_password_provider, &_authorized_key_handler);
|
||||||
|
}
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_NEED_GAME_PASSWORD, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_AUTH_REQUEST, TCP_MTU);
|
||||||
static_assert(std::tuple_size<decltype(keys.x25519_pub_key)>::value == 32);
|
this->authentication_handler->SendRequest(*p);
|
||||||
p->Send_binary(keys.x25519_pub_key);
|
|
||||||
p->Send_string(_settings_client.network.network_id);
|
this->SendPacket(std::move(p));
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Notify the client that the authentication has completed and tell that for the remainder of this socket encryption is enabled. */
|
||||||
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendEnableEncryption()
|
||||||
|
{
|
||||||
|
/* Invalid packet when status is anything but STATUS_AUTH_GAME. */
|
||||||
|
if (this->status != STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||||
|
|
||||||
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_ENABLE_ENCRYPTION, TCP_MTU);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -537,8 +548,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword()
|
|||||||
/** Request the company password. */
|
/** Request the company password. */
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedCompanyPassword()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedCompanyPassword()
|
||||||
{
|
{
|
||||||
/* Invalid packet when status is anything but STATUS_AUTH_GAME. */
|
/* Invalid packet when status is anything but STATUS_NEWGRFS_CHECK. */
|
||||||
if (this->status != STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
if (this->status != STATUS_NEWGRFS_CHECK) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||||
|
|
||||||
this->status = STATUS_AUTH_COMPANY;
|
this->status = STATUS_AUTH_COMPANY;
|
||||||
|
|
||||||
@@ -550,7 +561,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedCompanyPassword()
|
|||||||
/* Reset 'lag' counters */
|
/* Reset 'lag' counters */
|
||||||
this->last_frame = this->last_frame_server = _frame_counter;
|
this->last_frame = this->last_frame_server = _frame_counter;
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_NEED_COMPANY_PASSWORD, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_NEED_COMPANY_PASSWORD, TCP_MTU);
|
||||||
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
||||||
p->Send_string(_network_company_server_id);
|
p->Send_string(_network_company_server_id);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
@@ -572,7 +583,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome()
|
|||||||
|
|
||||||
const NetworkGameKeys &keys = this->GetKeys();
|
const NetworkGameKeys &keys = this->GetKeys();
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_WELCOME, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_WELCOME, TCP_MTU);
|
||||||
p->Send_uint32(this->client_id);
|
p->Send_uint32(this->client_id);
|
||||||
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
||||||
static_assert(std::tuple_size<decltype(keys.x25519_pub_key)>::value == 32);
|
static_assert(std::tuple_size<decltype(keys.x25519_pub_key)>::value == 32);
|
||||||
@@ -602,7 +613,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWait()
|
|||||||
if (new_cs->GetInfo()->join_date < this->GetInfo()->join_date || (new_cs->GetInfo()->join_date == this->GetInfo()->join_date && new_cs->client_id < this->client_id)) waiting++;
|
if (new_cs->GetInfo()->join_date < this->GetInfo()->join_date || (new_cs->GetInfo()->join_date == this->GetInfo()->join_date && new_cs->client_id < this->client_id)) waiting++;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_WAIT, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_WAIT, TCP_MTU);
|
||||||
p->Send_uint8(waiting);
|
p->Send_uint8(waiting);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
@@ -648,7 +659,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap()
|
|||||||
this->savegame = std::make_shared<PacketWriter>(this);
|
this->savegame = std::make_shared<PacketWriter>(this);
|
||||||
|
|
||||||
/* Now send the _frame_counter and how many packets are coming */
|
/* Now send the _frame_counter and how many packets are coming */
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_MAP_BEGIN, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_MAP_BEGIN, TCP_MTU);
|
||||||
p->Send_uint32(_frame_counter);
|
p->Send_uint32(_frame_counter);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
|
|
||||||
@@ -687,7 +698,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap()
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendJoin(ClientID client_id)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendJoin(ClientID client_id)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_JOIN, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_JOIN, TCP_MTU);
|
||||||
|
|
||||||
p->Send_uint32(client_id);
|
p->Send_uint32(client_id);
|
||||||
|
|
||||||
@@ -698,7 +709,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendJoin(ClientID client_id)
|
|||||||
/** Tell the client that they may run to a particular frame. */
|
/** Tell the client that they may run to a particular frame. */
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_FRAME, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_FRAME, TCP_MTU);
|
||||||
p->Send_uint32(_frame_counter);
|
p->Send_uint32(_frame_counter);
|
||||||
p->Send_uint32(_frame_counter_max);
|
p->Send_uint32(_frame_counter_max);
|
||||||
#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
|
#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
|
||||||
@@ -719,7 +730,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame()
|
|||||||
/** Request the client to sync. */
|
/** Request the client to sync. */
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendSync()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendSync()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_SYNC, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_SYNC, TCP_MTU);
|
||||||
p->Send_uint32(_frame_counter);
|
p->Send_uint32(_frame_counter);
|
||||||
p->Send_uint32(_sync_seed_1);
|
p->Send_uint32(_sync_seed_1);
|
||||||
|
|
||||||
@@ -734,7 +745,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendSync()
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendCommand(const CommandPacket &cp)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendCommand(const CommandPacket &cp)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_COMMAND, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_COMMAND, TCP_MTU);
|
||||||
|
|
||||||
this->NetworkGameSocketHandler::SendCommand(*p, cp);
|
this->NetworkGameSocketHandler::SendCommand(*p, cp);
|
||||||
p->Send_uint32(cp.frame);
|
p->Send_uint32(cp.frame);
|
||||||
@@ -756,7 +767,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendChat(NetworkAction action,
|
|||||||
{
|
{
|
||||||
if (this->status < STATUS_PRE_ACTIVE) return NETWORK_RECV_STATUS_OKAY;
|
if (this->status < STATUS_PRE_ACTIVE) return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_CHAT, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHAT, TCP_MTU);
|
||||||
|
|
||||||
p->Send_uint8 (action);
|
p->Send_uint8 (action);
|
||||||
p->Send_uint32(client_id);
|
p->Send_uint32(client_id);
|
||||||
@@ -779,7 +790,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendExternalChat(const std::st
|
|||||||
{
|
{
|
||||||
if (this->status < STATUS_PRE_ACTIVE) return NETWORK_RECV_STATUS_OKAY;
|
if (this->status < STATUS_PRE_ACTIVE) return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_EXTERNAL_CHAT, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_EXTERNAL_CHAT, TCP_MTU);
|
||||||
|
|
||||||
p->Send_string(source);
|
p->Send_string(source);
|
||||||
p->Send_uint16(colour);
|
p->Send_uint16(colour);
|
||||||
@@ -797,7 +808,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendExternalChat(const std::st
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendErrorQuit(ClientID client_id, NetworkErrorCode errorno)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendErrorQuit(ClientID client_id, NetworkErrorCode errorno)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_ERROR_QUIT, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_ERROR_QUIT, TCP_MTU);
|
||||||
|
|
||||||
p->Send_uint32(client_id);
|
p->Send_uint32(client_id);
|
||||||
p->Send_uint8 (errorno);
|
p->Send_uint8 (errorno);
|
||||||
@@ -812,7 +823,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendErrorQuit(ClientID client_
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendQuit(ClientID client_id)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendQuit(ClientID client_id)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_QUIT, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_QUIT, TCP_MTU);
|
||||||
|
|
||||||
p->Send_uint32(client_id);
|
p->Send_uint32(client_id);
|
||||||
|
|
||||||
@@ -823,7 +834,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendQuit(ClientID client_id)
|
|||||||
/** Tell the client we're shutting down. */
|
/** Tell the client we're shutting down. */
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendShutdown()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendShutdown()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_SHUTDOWN, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_SHUTDOWN, TCP_MTU);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -831,7 +842,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendShutdown()
|
|||||||
/** Tell the client we're starting a new game. */
|
/** Tell the client we're starting a new game. */
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGame()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGame()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_NEWGAME, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_NEWGAME, TCP_MTU);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -857,10 +868,10 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16_t colour
|
|||||||
std::array<uint8_t, 24> nonce;
|
std::array<uint8_t, 24> nonce;
|
||||||
RandomBytesWithFallback(nonce);
|
RandomBytesWithFallback(nonce);
|
||||||
|
|
||||||
/* Encrypt in place, use first half of hash as key */
|
/* Encrypt in place */
|
||||||
crypto_aead_lock(message.data(), mac.data(), this->rcon_reply_key, nonce.data(), nullptr, 0, message.data(), message.size());
|
crypto_aead_lock(message.data(), mac.data(), this->rcon_reply_key, nonce.data(), nullptr, 0, message.data(), message.size());
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_RCON, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_RCON, TCP_MTU);
|
||||||
static_assert(nonce.size() == 24);
|
static_assert(nonce.size() == 24);
|
||||||
static_assert(mac.size() == 16);
|
static_assert(mac.size() == 16);
|
||||||
p->Send_binary(nonce);
|
p->Send_binary(nonce);
|
||||||
@@ -876,7 +887,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16_t colour
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConDenied()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConDenied()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_RCON, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_RCON, TCP_MTU);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -888,7 +899,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConDenied()
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendMove(ClientID client_id, CompanyID company_id)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendMove(ClientID client_id, CompanyID company_id)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_MOVE, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_MOVE, TCP_MTU);
|
||||||
|
|
||||||
p->Send_uint32(client_id);
|
p->Send_uint32(client_id);
|
||||||
p->Send_uint8(company_id);
|
p->Send_uint8(company_id);
|
||||||
@@ -899,7 +910,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMove(ClientID client_id, C
|
|||||||
/** Send an update about the company password states. */
|
/** Send an update about the company password states. */
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyUpdate()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyUpdate()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_COMPANY_UPDATE, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_COMPANY_UPDATE, TCP_MTU);
|
||||||
|
|
||||||
static_assert(sizeof(_network_company_passworded) <= sizeof(uint16_t));
|
static_assert(sizeof(_network_company_passworded) <= sizeof(uint16_t));
|
||||||
p->Send_uint16(_network_company_passworded);
|
p->Send_uint16(_network_company_passworded);
|
||||||
@@ -910,7 +921,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyUpdate()
|
|||||||
/** Send an update about the max company/spectator counts. */
|
/** Send an update about the max company/spectator counts. */
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate()
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_CONFIG_UPDATE, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_CONFIG_UPDATE, TCP_MTU);
|
||||||
|
|
||||||
p->Send_uint8(_settings_client.network.max_companies);
|
p->Send_uint8(_settings_client.network.max_companies);
|
||||||
p->Send_string(_settings_client.network.server_name);
|
p->Send_string(_settings_client.network.server_name);
|
||||||
@@ -920,7 +931,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate()
|
|||||||
|
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendSettingsAccessUpdate(bool ok)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendSettingsAccessUpdate(bool ok)
|
||||||
{
|
{
|
||||||
auto p = std::make_unique<Packet>(PACKET_SERVER_SETTINGS_ACCESS, TCP_MTU);
|
auto p = std::make_unique<Packet>(this, PACKET_SERVER_SETTINGS_ACCESS, TCP_MTU);
|
||||||
p->Send_bool(ok);
|
p->Send_bool(ok);
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
@@ -950,7 +961,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED
|
|||||||
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->SendNeedGamePassword();
|
return this->SendNeedCompanyPassword();
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &p)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &p)
|
||||||
@@ -974,6 +985,13 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &p)
|
|||||||
return this->SendError(NETWORK_ERROR_WRONG_REVISION);
|
return this->SendError(NETWORK_ERROR_WRONG_REVISION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this->SendAuthRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_IDENTIFY(Packet &p)
|
||||||
|
{
|
||||||
|
if (this->status != STATUS_IDENTIFY) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||||
|
|
||||||
std::string client_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
|
std::string client_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
|
||||||
CompanyID playas = (Owner)p.Recv_uint8();
|
CompanyID playas = (Owner)p.Recv_uint8();
|
||||||
|
|
||||||
@@ -1024,22 +1042,52 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &p)
|
|||||||
return this->SendNewGRFCheck();
|
return this->SendNewGRFCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet &p)
|
static NetworkErrorCode GetErrorForAuthenticationMethod(NetworkAuthenticationMethod method)
|
||||||
|
{
|
||||||
|
switch (method) {
|
||||||
|
case NETWORK_AUTH_METHOD_X25519_PAKE:
|
||||||
|
return NETWORK_ERROR_WRONG_PASSWORD;
|
||||||
|
case NETWORK_AUTH_METHOD_X25519_AUTHORIZED_KEY:
|
||||||
|
return NETWORK_ERROR_NOT_ON_ALLOW_LIST;
|
||||||
|
|
||||||
|
default:
|
||||||
|
NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_AUTH_RESPONSE(Packet &p)
|
||||||
{
|
{
|
||||||
if (this->status != STATUS_AUTH_GAME) {
|
if (this->status != STATUS_AUTH_GAME) {
|
||||||
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check game password. Allow joining if we cleared the password meanwhile */
|
auto authentication_method = this->authentication_handler->GetAuthenticationMethod();
|
||||||
if (!_settings_client.network.server_password.empty()) {
|
switch (this->authentication_handler->ReceiveResponse(p)) {
|
||||||
NetworkSharedSecrets ss;
|
case NetworkAuthenticationServerHandler::AUTHENTICATED:
|
||||||
if (!this->ParseKeyPasswordPacket(p, ss, _settings_client.network.server_password, nullptr, 0)) {
|
break;
|
||||||
/* Password is invalid */
|
|
||||||
return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
|
case NetworkAuthenticationServerHandler::RETRY_NEXT_METHOD:
|
||||||
}
|
return this->SendAuthRequest();
|
||||||
|
|
||||||
|
case NetworkAuthenticationServerHandler::NOT_AUTHENTICATED:
|
||||||
|
default:
|
||||||
|
return this->SendError(GetErrorForAuthenticationMethod(authentication_method));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->SendNeedCompanyPassword();
|
NetworkRecvStatus status = this->SendEnableEncryption();
|
||||||
|
if (status != NETWORK_RECV_STATUS_OKAY) return status;
|
||||||
|
|
||||||
|
this->peer_public_key = this->authentication_handler->GetPeerPublicKey();
|
||||||
|
this->receive_encryption_handler = this->authentication_handler->CreateClientToServerEncryptionHandler();
|
||||||
|
this->send_encryption_handler = this->authentication_handler->CreateServerToClientEncryptionHandler();
|
||||||
|
this->authentication_handler = nullptr;
|
||||||
|
|
||||||
|
this->status = STATUS_IDENTIFY;
|
||||||
|
|
||||||
|
/* Reset 'lag' counters */
|
||||||
|
this->last_frame = this->last_frame_server = _frame_counter;
|
||||||
|
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet &p)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet &p)
|
||||||
@@ -1664,17 +1712,28 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet &p)
|
|||||||
{
|
{
|
||||||
if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||||
|
|
||||||
if (_settings_client.network.rcon_password.empty()) {
|
|
||||||
NetworkServerSendRconDenied(this->client_id);
|
|
||||||
return this->HandleAuthFailure(this->rcon_auth_failures);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string command;
|
std::string command;
|
||||||
NetworkSharedSecrets ss;
|
NetworkSharedSecrets ss;
|
||||||
if (!this->ParseKeyPasswordPacket(p, ss, _settings_client.network.rcon_password, &command, NETWORK_RCONCOMMAND_LENGTH)) {
|
bool done = false;
|
||||||
DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
|
if (_rcon_authorized_key_handler.IsAllowed(this->peer_public_key)) {
|
||||||
NetworkServerSendRconDenied(this->client_id);
|
/* We are allowed, try to handle using '*' password */
|
||||||
return this->HandleAuthFailure(this->rcon_auth_failures);
|
size_t saved_pos = p.GetDeserialisationPosition();
|
||||||
|
if (this->ParseKeyPasswordPacket(p, ss, "*", &command, NETWORK_RCONCOMMAND_LENGTH)) {
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
p.GetDeserialisationPosition() = saved_pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!done) {
|
||||||
|
if (_settings_client.network.rcon_password.empty()) {
|
||||||
|
NetworkServerSendRconDenied(this->client_id);
|
||||||
|
return this->HandleAuthFailure(this->rcon_auth_failures);
|
||||||
|
}
|
||||||
|
if (!this->ParseKeyPasswordPacket(p, ss, _settings_client.network.rcon_password, &command, NETWORK_RCONCOMMAND_LENGTH)) {
|
||||||
|
DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
|
||||||
|
NetworkServerSendRconDenied(this->client_id);
|
||||||
|
return this->HandleAuthFailure(this->rcon_auth_failures);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(net, 3, "[rcon] Client-id %d executed: %s", this->client_id, command.c_str());
|
DEBUG(net, 3, "[rcon] Client-id %d executed: %s", this->client_id, command.c_str());
|
||||||
@@ -1729,8 +1788,9 @@ const char *ServerNetworkGameSocketHandler::GetClientStatusName(ClientStatus sta
|
|||||||
{
|
{
|
||||||
static const char* _client_status_names[] {
|
static const char* _client_status_names[] {
|
||||||
"INACTIVE",
|
"INACTIVE",
|
||||||
"NEWGRFS_CHECK",
|
|
||||||
"AUTH_GAME",
|
"AUTH_GAME",
|
||||||
|
"IDENTIFY",
|
||||||
|
"NEWGRFS_CHECK",
|
||||||
"AUTH_COMPANY",
|
"AUTH_COMPANY",
|
||||||
"AUTHORIZED",
|
"AUTHORIZED",
|
||||||
"MAP_WAIT",
|
"MAP_WAIT",
|
||||||
@@ -2023,6 +2083,7 @@ void NetworkServer_Tick(bool send_frame)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NetworkClientSocket::STATUS_INACTIVE:
|
case NetworkClientSocket::STATUS_INACTIVE:
|
||||||
|
case NetworkClientSocket::STATUS_IDENTIFY:
|
||||||
case NetworkClientSocket::STATUS_NEWGRFS_CHECK:
|
case NetworkClientSocket::STATUS_NEWGRFS_CHECK:
|
||||||
case NetworkClientSocket::STATUS_AUTHORIZED:
|
case NetworkClientSocket::STATUS_AUTHORIZED:
|
||||||
/* NewGRF check and authorized states should be handled almost instantly.
|
/* NewGRF check and authorized states should be handled almost instantly.
|
||||||
@@ -2198,8 +2259,9 @@ void NetworkServerShowStatusToConsole()
|
|||||||
{
|
{
|
||||||
static const char * const stat_str[] = {
|
static const char * const stat_str[] = {
|
||||||
"inactive",
|
"inactive",
|
||||||
"checking NewGRFs",
|
|
||||||
"authorizing (server password)",
|
"authorizing (server password)",
|
||||||
|
"identifing client",
|
||||||
|
"checking NewGRFs",
|
||||||
"authorizing (company password)",
|
"authorizing (company password)",
|
||||||
"authorized",
|
"authorized",
|
||||||
"waiting",
|
"waiting",
|
||||||
@@ -2431,6 +2493,18 @@ void NetworkPrintClients()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the public key of the client with the given id.
|
||||||
|
* @param client_id The id of the client.
|
||||||
|
* @return View of the public key, which is empty when the client does not exist.
|
||||||
|
*/
|
||||||
|
std::string_view NetworkGetPublicKeyOfClient(ClientID client_id)
|
||||||
|
{
|
||||||
|
auto socket = NetworkClientSocket::GetByClientID(client_id);
|
||||||
|
return socket == nullptr ? "" : socket->GetPeerPublicKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform all the server specific administration of a new company.
|
* Perform all the server specific administration of a new company.
|
||||||
* @param c The newly created company; can't be nullptr.
|
* @param c The newly created company; can't be nullptr.
|
||||||
|
@@ -27,9 +27,13 @@ class ServerNetworkGameSocketHandler : public NetworkClientSocketPool::PoolItem<
|
|||||||
uint8_t *rcon_reply_key = nullptr;
|
uint8_t *rcon_reply_key = nullptr;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
std::unique_ptr<class NetworkAuthenticationServerHandler> authentication_handler; ///< The handler for the authentication.
|
||||||
|
std::string peer_public_key; ///< The public key of our client.
|
||||||
|
|
||||||
NetworkRecvStatus Receive_CLIENT_JOIN(Packet &p) override;
|
NetworkRecvStatus Receive_CLIENT_JOIN(Packet &p) override;
|
||||||
|
NetworkRecvStatus Receive_CLIENT_IDENTIFY(Packet &p) override;
|
||||||
NetworkRecvStatus Receive_CLIENT_GAME_INFO(Packet &p) override;
|
NetworkRecvStatus Receive_CLIENT_GAME_INFO(Packet &p) override;
|
||||||
NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet &p) override;
|
NetworkRecvStatus Receive_CLIENT_AUTH_RESPONSE(Packet &p) override;
|
||||||
NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet &p) override;
|
NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet &p) override;
|
||||||
NetworkRecvStatus Receive_CLIENT_SETTINGS_PASSWORD(Packet &p) override;
|
NetworkRecvStatus Receive_CLIENT_SETTINGS_PASSWORD(Packet &p) override;
|
||||||
NetworkRecvStatus Receive_CLIENT_GETMAP(Packet &p) override;
|
NetworkRecvStatus Receive_CLIENT_GETMAP(Packet &p) override;
|
||||||
@@ -52,7 +56,8 @@ protected:
|
|||||||
NetworkRecvStatus SendGameInfoExtended(PacketGameType reply_type, uint16_t flags, uint16_t version);
|
NetworkRecvStatus SendGameInfoExtended(PacketGameType reply_type, uint16_t flags, uint16_t version);
|
||||||
NetworkRecvStatus SendNewGRFCheck();
|
NetworkRecvStatus SendNewGRFCheck();
|
||||||
NetworkRecvStatus SendWelcome();
|
NetworkRecvStatus SendWelcome();
|
||||||
NetworkRecvStatus SendNeedGamePassword();
|
NetworkRecvStatus SendAuthRequest();
|
||||||
|
NetworkRecvStatus SendEnableEncryption();
|
||||||
NetworkRecvStatus SendNeedCompanyPassword();
|
NetworkRecvStatus SendNeedCompanyPassword();
|
||||||
|
|
||||||
bool ParseKeyPasswordPacket(Packet &p, NetworkSharedSecrets &ss, const std::string &password, std::string *payload, size_t length);
|
bool ParseKeyPasswordPacket(Packet &p, NetworkSharedSecrets &ss, const std::string &password, std::string *payload, size_t length);
|
||||||
@@ -61,8 +66,9 @@ public:
|
|||||||
/** Status of a client */
|
/** Status of a client */
|
||||||
enum ClientStatus {
|
enum ClientStatus {
|
||||||
STATUS_INACTIVE, ///< The client is not connected nor active.
|
STATUS_INACTIVE, ///< The client is not connected nor active.
|
||||||
STATUS_NEWGRFS_CHECK, ///< The client is checking NewGRFs.
|
|
||||||
STATUS_AUTH_GAME, ///< The client is authorizing with game (server) password.
|
STATUS_AUTH_GAME, ///< The client is authorizing with game (server) password.
|
||||||
|
STATUS_IDENTIFY, ///< The client is identifying itself.
|
||||||
|
STATUS_NEWGRFS_CHECK, ///< The client is checking NewGRFs.
|
||||||
STATUS_AUTH_COMPANY, ///< The client is authorizing with company password.
|
STATUS_AUTH_COMPANY, ///< The client is authorizing with company password.
|
||||||
STATUS_AUTHORIZED, ///< The client is authorized.
|
STATUS_AUTHORIZED, ///< The client is authorized.
|
||||||
STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map.
|
STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map.
|
||||||
@@ -150,6 +156,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *GetClientIP();
|
const char *GetClientIP();
|
||||||
|
std::string_view GetPeerPublicKey() const { return this->peer_public_key; }
|
||||||
|
|
||||||
static ServerNetworkGameSocketHandler *GetByClientID(ClientID client_id);
|
static ServerNetworkGameSocketHandler *GetByClientID(ClientID client_id);
|
||||||
};
|
};
|
||||||
|
@@ -86,7 +86,7 @@ std::unique_ptr<ClientNetworkStunSocketHandler> ClientNetworkStunSocketHandler::
|
|||||||
|
|
||||||
stun_handler->Connect(token, family);
|
stun_handler->Connect(token, family);
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_STUN_SERCLI_STUN);
|
auto p = std::make_unique<Packet>(stun_handler.get(), PACKET_STUN_SERCLI_STUN);
|
||||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||||
p->Send_string(token);
|
p->Send_string(token);
|
||||||
p->Send_uint8(family);
|
p->Send_uint8(family);
|
||||||
|
@@ -100,7 +100,7 @@ void ClientNetworkTurnSocketHandler::Connect()
|
|||||||
{
|
{
|
||||||
auto turn_handler = std::make_unique<ClientNetworkTurnSocketHandler>(token, tracking_number, connection_string);
|
auto turn_handler = std::make_unique<ClientNetworkTurnSocketHandler>(token, tracking_number, connection_string);
|
||||||
|
|
||||||
auto p = std::make_unique<Packet>(PACKET_TURN_SERCLI_CONNECT);
|
auto p = std::make_unique<Packet>(turn_handler.get(), PACKET_TURN_SERCLI_CONNECT);
|
||||||
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
|
||||||
p->Send_string(ticket);
|
p->Send_string(ticket);
|
||||||
|
|
||||||
|
@@ -146,6 +146,7 @@ enum NetworkErrorCode {
|
|||||||
NETWORK_ERROR_TIMEOUT_MAP,
|
NETWORK_ERROR_TIMEOUT_MAP,
|
||||||
NETWORK_ERROR_TIMEOUT_JOIN,
|
NETWORK_ERROR_TIMEOUT_JOIN,
|
||||||
NETWORK_ERROR_INVALID_CLIENT_NAME,
|
NETWORK_ERROR_INVALID_CLIENT_NAME,
|
||||||
|
NETWORK_ERROR_NOT_ON_ALLOW_LIST,
|
||||||
|
|
||||||
NETWORK_ERROR_END,
|
NETWORK_ERROR_END,
|
||||||
};
|
};
|
||||||
|
@@ -60,9 +60,9 @@ struct UDPSocket {
|
|||||||
static UDPSocket _udp_client("Client"); ///< udp client socket
|
static UDPSocket _udp_client("Client"); ///< udp client socket
|
||||||
static UDPSocket _udp_server("Server"); ///< udp server socket
|
static UDPSocket _udp_server("Server"); ///< udp server socket
|
||||||
|
|
||||||
static Packet PrepareUdpClientFindServerPacket()
|
static Packet PrepareUdpClientFindServerPacket(NetworkUDPSocketHandler *socket)
|
||||||
{
|
{
|
||||||
Packet p(PACKET_UDP_CLIENT_FIND_SERVER);
|
Packet p(socket, PACKET_UDP_CLIENT_FIND_SERVER);
|
||||||
p.Send_uint32(FIND_SERVER_EXTENDED_TOKEN);
|
p.Send_uint32(FIND_SERVER_EXTENDED_TOKEN);
|
||||||
p.Send_uint16(0); // flags
|
p.Send_uint16(0); // flags
|
||||||
p.Send_uint16(0); // version
|
p.Send_uint16(0); // version
|
||||||
@@ -92,7 +92,7 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet &p, Networ
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet packet(PACKET_UDP_SERVER_RESPONSE);
|
Packet packet(this, PACKET_UDP_SERVER_RESPONSE);
|
||||||
this->SendPacket(packet, client_addr);
|
this->SendPacket(packet, client_addr);
|
||||||
|
|
||||||
DEBUG(net, 7, "Queried from %s", client_addr.GetHostname());
|
DEBUG(net, 7, "Queried from %s", client_addr.GetHostname());
|
||||||
@@ -103,7 +103,7 @@ void ServerNetworkUDPSocketHandler::Reply_CLIENT_FIND_SERVER_extended(Packet &p,
|
|||||||
[[maybe_unused]] uint16_t flags = p.Recv_uint16();
|
[[maybe_unused]] uint16_t flags = p.Recv_uint16();
|
||||||
uint16_t version = p.Recv_uint16();
|
uint16_t version = p.Recv_uint16();
|
||||||
|
|
||||||
Packet packet(PACKET_UDP_EX_SERVER_RESPONSE);
|
Packet packet(this, PACKET_UDP_EX_SERVER_RESPONSE);
|
||||||
this->SendPacket(packet, client_addr);
|
this->SendPacket(packet, client_addr);
|
||||||
|
|
||||||
DEBUG(net, 7, "Queried (extended: %u) from %s", version, client_addr.GetHostname());
|
DEBUG(net, 7, "Queried (extended: %u) from %s", version, client_addr.GetHostname());
|
||||||
@@ -140,7 +140,7 @@ static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket)
|
|||||||
for (NetworkAddress &addr : _broadcast_list) {
|
for (NetworkAddress &addr : _broadcast_list) {
|
||||||
DEBUG(net, 5, "Broadcasting to %s", addr.GetHostname());
|
DEBUG(net, 5, "Broadcasting to %s", addr.GetHostname());
|
||||||
|
|
||||||
Packet p = PrepareUdpClientFindServerPacket();
|
Packet p = PrepareUdpClientFindServerPacket(socket);
|
||||||
socket->SendPacket(p, addr, true, true);
|
socket->SendPacket(p, addr, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -197,6 +197,8 @@ private:
|
|||||||
"newgrf",
|
"newgrf",
|
||||||
"servers",
|
"servers",
|
||||||
"server_bind_addresses",
|
"server_bind_addresses",
|
||||||
|
"server_authorized_keys",
|
||||||
|
"rcon_authorized_keys",
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -2778,6 +2780,8 @@ static void HandlePrivateSettingDescs(IniFile &private_ini, SettingDescProc *pro
|
|||||||
proc_list(private_ini, "server_bind_addresses", _network_bind_list);
|
proc_list(private_ini, "server_bind_addresses", _network_bind_list);
|
||||||
proc_list(private_ini, "servers", _network_host_list);
|
proc_list(private_ini, "servers", _network_host_list);
|
||||||
proc_list(private_ini, "bans", _network_ban_list);
|
proc_list(private_ini, "bans", _network_ban_list);
|
||||||
|
proc_list(private_ini, "server_authorized_keys", _settings_client.network.server_authorized_keys);
|
||||||
|
proc_list(private_ini, "rcon_authorized_keys", _settings_client.network.rcon_authorized_keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -435,10 +435,14 @@ struct NetworkSettings {
|
|||||||
std::string server_invite_code_secret; ///< Secret to proof we got this invite code from the Game Coordinator.
|
std::string server_invite_code_secret; ///< Secret to proof we got this invite code from the Game Coordinator.
|
||||||
std::string server_name; ///< name of the server
|
std::string server_name; ///< name of the server
|
||||||
std::string server_password; ///< password for joining this server
|
std::string server_password; ///< password for joining this server
|
||||||
|
std::vector<std::string> server_authorized_keys; ///< Public keys of clients that are authorized to connect to the game.
|
||||||
std::string rcon_password; ///< password for rconsole (server side)
|
std::string rcon_password; ///< password for rconsole (server side)
|
||||||
|
std::vector<std::string> rcon_authorized_keys; ///< Public keys of clients that are authorized to use the rconsole (server side).
|
||||||
std::string admin_password; ///< password for the admin network
|
std::string admin_password; ///< password for the admin network
|
||||||
std::string settings_password; ///< password for game settings (server side)
|
std::string settings_password; ///< password for game settings (server side)
|
||||||
std::string client_name; ///< name of the player (as client)
|
std::string client_name; ///< name of the player (as client)
|
||||||
|
std::string client_secret_key; ///< The secret key of the client for authorized key logins.
|
||||||
|
std::string client_public_key; ///< The public key of the client for authorized key logins.
|
||||||
std::string default_company_pass; ///< default password for new companies in encrypted form
|
std::string default_company_pass; ///< default password for new companies in encrypted form
|
||||||
std::string connect_to_ip; ///< default for the "Add server" query
|
std::string connect_to_ip; ///< default for the "Add server" query
|
||||||
std::string network_id; ///< network ID for servers
|
std::string network_id; ///< network ID for servers
|
||||||
|
@@ -75,6 +75,24 @@ def = nullptr
|
|||||||
pre_cb = ReplaceAsteriskWithEmptyPassword
|
pre_cb = ReplaceAsteriskWithEmptyPassword
|
||||||
cat = SC_EXPERT
|
cat = SC_EXPERT
|
||||||
|
|
||||||
|
[SDTC_SSTR]
|
||||||
|
var = network.client_secret_key
|
||||||
|
type = SLE_STR
|
||||||
|
length = NETWORK_SECRET_KEY_LENGTH
|
||||||
|
flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
|
||||||
|
def = nullptr
|
||||||
|
; Prevent the user from setting the secret key from the console using 'setting'
|
||||||
|
pre_cb = [](auto) { return false; }
|
||||||
|
|
||||||
|
[SDTC_SSTR]
|
||||||
|
var = network.client_public_key
|
||||||
|
type = SLE_STR
|
||||||
|
length = NETWORK_SECRET_KEY_LENGTH
|
||||||
|
flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
|
||||||
|
def = nullptr
|
||||||
|
; Prevent the user from setting the public key from the console using 'setting'
|
||||||
|
pre_cb = [](auto) { return false; }
|
||||||
|
|
||||||
[SDTC_SSTR]
|
[SDTC_SSTR]
|
||||||
var = network.default_company_pass
|
var = network.default_company_pass
|
||||||
type = SLE_STR
|
type = SLE_STR
|
||||||
|
@@ -10,6 +10,7 @@ add_test_files(
|
|||||||
string_func.cpp
|
string_func.cpp
|
||||||
strings_func.cpp
|
strings_func.cpp
|
||||||
test_main.cpp
|
test_main.cpp
|
||||||
|
test_network_crypto.cpp
|
||||||
test_script_admin.cpp
|
test_script_admin.cpp
|
||||||
test_window_desc.cpp
|
test_window_desc.cpp
|
||||||
)
|
)
|
||||||
|
271
src/tests/test_network_crypto.cpp
Normal file
271
src/tests/test_network_crypto.cpp
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file test_network_crypto.cpp Tests for network related crypto functions. */
|
||||||
|
|
||||||
|
#include "../stdafx.h"
|
||||||
|
|
||||||
|
#include "../3rdparty/catch2/catch.hpp"
|
||||||
|
|
||||||
|
#include "../core/format.hpp"
|
||||||
|
#include "../network/network_crypto_internal.h"
|
||||||
|
#include "../network/core/packet.h"
|
||||||
|
#include "../string_func.h"
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
/* The length of the hexadecimal representation of a X25519 key must fit in the key length. */
|
||||||
|
static_assert(NETWORK_SECRET_KEY_LENGTH >= X25519_KEY_SIZE * 2 + 1);
|
||||||
|
|
||||||
|
class MockNetworkSocketHandler : public NetworkSocketHandler {
|
||||||
|
public:
|
||||||
|
MockNetworkSocketHandler(std::unique_ptr<NetworkEncryptionHandler> &&receive = {}, std::unique_ptr<NetworkEncryptionHandler> &&send = {})
|
||||||
|
{
|
||||||
|
this->receive_encryption_handler = std::move(receive);
|
||||||
|
this->send_encryption_handler = std::move(send);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static MockNetworkSocketHandler mock_socket_handler;
|
||||||
|
|
||||||
|
static std::tuple<Packet, bool> CreatePacketForReading(Packet &source, MockNetworkSocketHandler *socket_handler)
|
||||||
|
{
|
||||||
|
source.PrepareToSend();
|
||||||
|
|
||||||
|
Packet dest(Packet::ReadTag{}, socket_handler, COMPAT_MTU, source.Size());
|
||||||
|
|
||||||
|
auto transfer_in = [](Packet &source, char *dest_data, size_t length) {
|
||||||
|
auto transfer_out = [](char *dest_data, const char *source_data, size_t length) {
|
||||||
|
std::copy(source_data, source_data + length, dest_data);
|
||||||
|
return length;
|
||||||
|
};
|
||||||
|
return source.TransferOutWithLimit(transfer_out, length, dest_data);
|
||||||
|
};
|
||||||
|
dest.TransferIn(transfer_in, source);
|
||||||
|
|
||||||
|
bool valid = dest.PrepareToRead();
|
||||||
|
dest.Recv_uint8(); // Ignore the type
|
||||||
|
return { dest, valid };
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestPasswordRequestHandler : public NetworkAuthenticationPasswordRequestHandler {
|
||||||
|
private:
|
||||||
|
std::string password;
|
||||||
|
public:
|
||||||
|
TestPasswordRequestHandler(std::string &password) : password(password) {}
|
||||||
|
void SendResponse() override {}
|
||||||
|
void AskUserForPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request) override { request->Reply(this->password); }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void TestAuthentication(NetworkAuthenticationServerHandler &server, NetworkAuthenticationClientHandler &client,
|
||||||
|
NetworkAuthenticationServerHandler::ResponseResult expected_response_result,
|
||||||
|
NetworkAuthenticationClientHandler::RequestResult expected_request_result)
|
||||||
|
{
|
||||||
|
Packet request(&mock_socket_handler, PacketType{});
|
||||||
|
server.SendRequest(request);
|
||||||
|
|
||||||
|
bool valid;
|
||||||
|
std::tie(request, valid) = CreatePacketForReading(request, &mock_socket_handler);
|
||||||
|
CHECK(valid);
|
||||||
|
CHECK(client.ReceiveRequest(request) == expected_request_result);
|
||||||
|
|
||||||
|
Packet response(&mock_socket_handler, PacketType{});
|
||||||
|
client.SendResponse(response);
|
||||||
|
|
||||||
|
std::tie(response, valid) = CreatePacketForReading(response, &mock_socket_handler);
|
||||||
|
CHECK(valid);
|
||||||
|
CHECK(server.ReceiveResponse(response) == expected_response_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("Authentication_KeyExchangeOnly")
|
||||||
|
{
|
||||||
|
X25519KeyExchangeOnlyServerHandler server(X25519SecretKey::CreateRandom());
|
||||||
|
X25519KeyExchangeOnlyClientHandler client(X25519SecretKey::CreateRandom());
|
||||||
|
|
||||||
|
TestAuthentication(server, client, NetworkAuthenticationServerHandler::AUTHENTICATED, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void TestAuthenticationPAKE(std::string server_password, std::string client_password,
|
||||||
|
NetworkAuthenticationServerHandler::ResponseResult expected_response_result)
|
||||||
|
{
|
||||||
|
NetworkAuthenticationDefaultPasswordProvider server_password_provider(server_password);
|
||||||
|
X25519PAKEServerHandler server(X25519SecretKey::CreateRandom(), &server_password_provider);
|
||||||
|
X25519PAKEClientHandler client(X25519SecretKey::CreateRandom(), std::make_shared<TestPasswordRequestHandler>(client_password));
|
||||||
|
|
||||||
|
TestAuthentication(server, client, expected_response_result, NetworkAuthenticationClientHandler::AWAIT_USER_INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Authentication_PAKE")
|
||||||
|
{
|
||||||
|
SECTION("Correct password") {
|
||||||
|
TestAuthenticationPAKE("sikrit", "sikrit", NetworkAuthenticationServerHandler::AUTHENTICATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Empty password") {
|
||||||
|
TestAuthenticationPAKE("", "", NetworkAuthenticationServerHandler::AUTHENTICATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Wrong password") {
|
||||||
|
TestAuthenticationPAKE("sikrit", "secret", NetworkAuthenticationServerHandler::NOT_AUTHENTICATED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void TestAuthenticationAuthorizedKey(const X25519SecretKey &client_secret_key, const X25519PublicKey &server_expected_public_key,
|
||||||
|
NetworkAuthenticationServerHandler::ResponseResult expected_response_result)
|
||||||
|
{
|
||||||
|
std::vector<std::string> authorized_keys;
|
||||||
|
authorized_keys.emplace_back(FormatArrayAsHex(server_expected_public_key));
|
||||||
|
|
||||||
|
NetworkAuthenticationDefaultAuthorizedKeyHandler authorized_key_handler(authorized_keys);
|
||||||
|
X25519AuthorizedKeyServerHandler server(X25519SecretKey::CreateRandom(), &authorized_key_handler);
|
||||||
|
X25519AuthorizedKeyClientHandler client(client_secret_key);
|
||||||
|
|
||||||
|
TestAuthentication(server, client, expected_response_result, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Authentication_AuthorizedKey")
|
||||||
|
{
|
||||||
|
auto client_secret_key = X25519SecretKey::CreateRandom();
|
||||||
|
auto valid_client_public_key = client_secret_key.CreatePublicKey();
|
||||||
|
auto invalid_client_public_key = X25519SecretKey::CreateRandom().CreatePublicKey();
|
||||||
|
|
||||||
|
SECTION("Correct public key") {
|
||||||
|
TestAuthenticationAuthorizedKey(client_secret_key, valid_client_public_key, NetworkAuthenticationServerHandler::AUTHENTICATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Incorrect public key") {
|
||||||
|
TestAuthenticationAuthorizedKey(client_secret_key, invalid_client_public_key, NetworkAuthenticationServerHandler::NOT_AUTHENTICATED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("Authentication_Combined")
|
||||||
|
{
|
||||||
|
auto client_secret_key = X25519SecretKey::CreateRandom();
|
||||||
|
std::string client_secret_key_str = FormatArrayAsHex(client_secret_key);
|
||||||
|
auto client_public_key = client_secret_key.CreatePublicKey();
|
||||||
|
std::string client_public_key_str = FormatArrayAsHex(client_public_key);
|
||||||
|
|
||||||
|
std::vector<std::string> valid_authorized_keys;
|
||||||
|
valid_authorized_keys.emplace_back(client_public_key_str);
|
||||||
|
NetworkAuthenticationDefaultAuthorizedKeyHandler valid_authorized_key_handler(valid_authorized_keys);
|
||||||
|
|
||||||
|
std::vector<std::string> invalid_authorized_keys;
|
||||||
|
invalid_authorized_keys.emplace_back("not-a-valid-authorized-key");
|
||||||
|
NetworkAuthenticationDefaultAuthorizedKeyHandler invalid_authorized_key_handler(invalid_authorized_keys);
|
||||||
|
|
||||||
|
std::vector<std::string> no_authorized_keys;
|
||||||
|
NetworkAuthenticationDefaultAuthorizedKeyHandler no_authorized_key_handler(no_authorized_keys);
|
||||||
|
|
||||||
|
std::string no_password = "";
|
||||||
|
NetworkAuthenticationDefaultPasswordProvider no_password_provider(no_password);
|
||||||
|
std::string valid_password = "sikrit";
|
||||||
|
NetworkAuthenticationDefaultPasswordProvider valid_password_provider(valid_password);
|
||||||
|
std::string invalid_password = "secret";
|
||||||
|
NetworkAuthenticationDefaultPasswordProvider invalid_password_provider(invalid_password);
|
||||||
|
|
||||||
|
auto client = NetworkAuthenticationClientHandler::Create(std::make_shared<TestPasswordRequestHandler>(valid_password), client_secret_key_str, client_public_key_str);
|
||||||
|
|
||||||
|
SECTION("Invalid authorized keys, invalid password") {
|
||||||
|
auto server = NetworkAuthenticationServerHandler::Create(&invalid_password_provider, &invalid_authorized_key_handler);
|
||||||
|
|
||||||
|
TestAuthentication(*server, *client, NetworkAuthenticationServerHandler::RETRY_NEXT_METHOD, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE);
|
||||||
|
TestAuthentication(*server, *client, NetworkAuthenticationServerHandler::NOT_AUTHENTICATED, NetworkAuthenticationClientHandler::AWAIT_USER_INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Invalid authorized keys, valid password") {
|
||||||
|
auto server = NetworkAuthenticationServerHandler::Create(&valid_password_provider, &invalid_authorized_key_handler);
|
||||||
|
|
||||||
|
TestAuthentication(*server, *client, NetworkAuthenticationServerHandler::RETRY_NEXT_METHOD, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE);
|
||||||
|
TestAuthentication(*server, *client, NetworkAuthenticationServerHandler::AUTHENTICATED, NetworkAuthenticationClientHandler::AWAIT_USER_INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Valid authorized keys, valid password") {
|
||||||
|
auto server = NetworkAuthenticationServerHandler::Create(&valid_password_provider, &valid_authorized_key_handler);
|
||||||
|
|
||||||
|
TestAuthentication(*server, *client, NetworkAuthenticationServerHandler::AUTHENTICATED, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("No authorized keys, invalid password") {
|
||||||
|
auto server = NetworkAuthenticationServerHandler::Create(&invalid_password_provider, &no_authorized_key_handler);
|
||||||
|
|
||||||
|
TestAuthentication(*server, *client, NetworkAuthenticationServerHandler::NOT_AUTHENTICATED, NetworkAuthenticationClientHandler::AWAIT_USER_INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("No authorized keys, valid password") {
|
||||||
|
auto server = NetworkAuthenticationServerHandler::Create(&valid_password_provider, &no_authorized_key_handler);
|
||||||
|
|
||||||
|
TestAuthentication(*server, *client, NetworkAuthenticationServerHandler::AUTHENTICATED, NetworkAuthenticationClientHandler::AWAIT_USER_INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("No authorized keys, no password") {
|
||||||
|
auto server = NetworkAuthenticationServerHandler::Create(&no_password_provider, &no_authorized_key_handler);
|
||||||
|
|
||||||
|
TestAuthentication(*server, *client, NetworkAuthenticationServerHandler::AUTHENTICATED, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void CheckEncryption(MockNetworkSocketHandler *sending_socket_handler, MockNetworkSocketHandler *receiving_socket_handler)
|
||||||
|
{
|
||||||
|
PacketType sent_packet_type{ 1 };
|
||||||
|
uint64_t sent_value = 0x1234567890ABCDEF;
|
||||||
|
std::set<PacketType> encrypted_packet_types;
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
Packet request(sending_socket_handler, sent_packet_type);
|
||||||
|
request.Send_uint64(sent_value);
|
||||||
|
|
||||||
|
auto [response, valid] = CreatePacketForReading(request, receiving_socket_handler);
|
||||||
|
CHECK(valid);
|
||||||
|
CHECK(response.Recv_uint64() == sent_value);
|
||||||
|
|
||||||
|
encrypted_packet_types.insert(request.GetPacketType());
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check whether it looks like encryption has happened. This is done by checking the value
|
||||||
|
* of the packet type after encryption. If after a few iterations more than one encrypted
|
||||||
|
* value has been seen, then we know that some type of encryption/scrambling is happening.
|
||||||
|
*
|
||||||
|
* Technically this check could fail erroneously when 16 subsequent encryptions yield the
|
||||||
|
* same encrypted packet type. However, with encryption that byte should have random value
|
||||||
|
* value, so the chance of this happening are tiny given enough iterations.
|
||||||
|
* Roughly in the order of 2**((iterations - 1) * 8), which with 10 iterations is in the
|
||||||
|
* one-in-sextillion (10**21) order of magnitude.
|
||||||
|
*/
|
||||||
|
CHECK(encrypted_packet_types.size() != 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Encryption handling")
|
||||||
|
{
|
||||||
|
X25519KeyExchangeOnlyServerHandler server(X25519SecretKey::CreateRandom());
|
||||||
|
X25519KeyExchangeOnlyClientHandler client(X25519SecretKey::CreateRandom());
|
||||||
|
|
||||||
|
TestAuthentication(server, client, NetworkAuthenticationServerHandler::AUTHENTICATED, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE);
|
||||||
|
|
||||||
|
MockNetworkSocketHandler server_socket_handler(server.CreateClientToServerEncryptionHandler(), server.CreateServerToClientEncryptionHandler());
|
||||||
|
MockNetworkSocketHandler client_socket_handler(client.CreateServerToClientEncryptionHandler(), client.CreateClientToServerEncryptionHandler());
|
||||||
|
|
||||||
|
SECTION("Encyption happening client -> server") {
|
||||||
|
CheckEncryption(&client_socket_handler, &server_socket_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Encyption happening server -> client") {
|
||||||
|
CheckEncryption(&server_socket_handler, &client_socket_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Unencrypted packet sent causes invalid read packet") {
|
||||||
|
Packet request(&mock_socket_handler, PacketType{});
|
||||||
|
request.Send_uint64(0);
|
||||||
|
|
||||||
|
auto [response, valid] = CreatePacketForReading(request, &client_socket_handler);
|
||||||
|
CHECK(!valid);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user