mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 10:31:29 +00:00
[Netcode] Remove security from servertalk connections (#1464)
* Remove security from servertalk connections * Remove the two hello steps before handshake that are now obsolete out * Revert "Remove the two hello steps before handshake that are now obsolete out" This reverts commit 32d61ea2381c1bddf8b08c5240899116d0fd3e80. * Keep old values for enums * Use downgrade security handshake for backwards compat * Send handshake instead of hello to fast connect * Add connect callback so it will actually work
This commit is contained in:
parent
bde5d6931c
commit
1c8231eb9e
@ -22,31 +22,10 @@ EQ::Net::ServertalkClient::~ServertalkClient()
|
|||||||
void EQ::Net::ServertalkClient::Send(uint16_t opcode, EQ::Net::Packet &p)
|
void EQ::Net::ServertalkClient::Send(uint16_t opcode, EQ::Net::Packet &p)
|
||||||
{
|
{
|
||||||
EQ::Net::DynamicPacket out;
|
EQ::Net::DynamicPacket out;
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (m_encrypted) {
|
|
||||||
if (p.Length() == 0) {
|
|
||||||
p.PutUInt8(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
out.PutUInt32(0, p.Length() + crypto_secretbox_MACBYTES);
|
|
||||||
out.PutUInt16(4, opcode);
|
|
||||||
|
|
||||||
std::unique_ptr<unsigned char[]> cipher(new unsigned char[p.Length() + crypto_secretbox_MACBYTES]);
|
|
||||||
|
|
||||||
crypto_box_easy_afternm(&cipher[0], (unsigned char*)p.Data(), p.Length(), m_nonce_ours, m_shared_key);
|
|
||||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
|
||||||
out.PutData(6, &cipher[0], p.Length() + crypto_secretbox_MACBYTES);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.PutUInt32(0, p.Length());
|
|
||||||
out.PutUInt16(4, opcode);
|
|
||||||
out.PutPacket(6, p);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
out.PutUInt32(0, p.Length());
|
out.PutUInt32(0, p.Length());
|
||||||
out.PutUInt16(4, opcode);
|
out.PutUInt16(4, opcode);
|
||||||
out.PutPacket(6, p);
|
out.PutPacket(6, p);
|
||||||
#endif
|
|
||||||
InternalSend(ServertalkMessage, out);
|
InternalSend(ServertalkMessage, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,14 +66,18 @@ void EQ::Net::ServertalkClient::Connect()
|
|||||||
m_connection = connection;
|
m_connection = connection;
|
||||||
m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) {
|
m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) {
|
||||||
LogF(Logs::General, Logs::TCPConnection, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
LogF(Logs::General, Logs::TCPConnection, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||||
m_encrypted = false;
|
|
||||||
m_connection.reset();
|
m_connection.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
m_connection->OnRead(std::bind(&EQ::Net::ServertalkClient::ProcessData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
m_connection->OnRead(std::bind(&EQ::Net::ServertalkClient::ProcessData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||||
m_connection->Start();
|
m_connection->Start();
|
||||||
|
|
||||||
SendHello();
|
SendHandshake();
|
||||||
|
|
||||||
|
if (m_on_connect_cb) {
|
||||||
|
m_on_connect_cb(this);
|
||||||
|
}
|
||||||
|
|
||||||
m_connecting = false;
|
m_connecting = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -188,67 +171,11 @@ void EQ::Net::ServertalkClient::ProcessReadBuffer()
|
|||||||
|
|
||||||
void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
|
||||||
memset(m_nonce_ours, 0, crypto_box_NONCEBYTES);
|
|
||||||
memset(m_nonce_theirs, 0, crypto_box_NONCEBYTES);
|
|
||||||
memset(m_shared_key, 0, crypto_box_BEFORENMBYTES);
|
|
||||||
m_encrypted = false;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
SendHandshake();
|
||||||
|
|
||||||
if (enc) {
|
|
||||||
if (p.Length() == (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)) {
|
|
||||||
memcpy(m_public_key_theirs, (char*)p.Data() + 1, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memcpy(m_nonce_theirs, (char*)p.Data() + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);
|
|
||||||
m_encrypted = true;
|
|
||||||
|
|
||||||
SendHandshake();
|
|
||||||
|
|
||||||
if (m_on_connect_cb) {
|
|
||||||
m_on_connect_cb(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LogError("Could not process hello, size != {0}", 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SendHandshake();
|
|
||||||
|
|
||||||
if (m_on_connect_cb) {
|
|
||||||
m_on_connect_cb(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (std::exception &ex) {
|
|
||||||
LogError("Error parsing hello from server: {0}", ex.what());
|
|
||||||
m_connection->Disconnect();
|
|
||||||
|
|
||||||
if (m_on_connect_cb) {
|
if (m_on_connect_cb) {
|
||||||
m_on_connect_cb(nullptr);
|
m_on_connect_cb(this);
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
try {
|
|
||||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
|
||||||
|
|
||||||
if (enc) {
|
|
||||||
SendHandshake(true);
|
|
||||||
|
|
||||||
if (m_on_connect_cb) {
|
|
||||||
m_on_connect_cb(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SendHandshake();
|
|
||||||
|
|
||||||
if (m_on_connect_cb) {
|
|
||||||
m_on_connect_cb(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
@ -259,7 +186,6 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
|||||||
m_on_connect_cb(nullptr);
|
m_on_connect_cb(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||||
@ -269,45 +195,7 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
|||||||
auto opcode = p.GetUInt16(4);
|
auto opcode = p.GetUInt16(4);
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
auto data = p.GetString(6, length);
|
auto data = p.GetString(6, length);
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (m_encrypted) {
|
|
||||||
size_t message_len = length - crypto_secretbox_MACBYTES;
|
|
||||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
|
||||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
|
|
||||||
{
|
|
||||||
LogError("Error decrypting message from server");
|
|
||||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EQ::Net::StaticPacket decrypted_packet(&decrypted_text[0], message_len);
|
|
||||||
|
|
||||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
|
||||||
|
|
||||||
auto cb = m_message_callbacks.find(opcode);
|
|
||||||
if (cb != m_message_callbacks.end()) {
|
|
||||||
cb->second(opcode, decrypted_packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_message_callback) {
|
|
||||||
m_message_callback(opcode, decrypted_packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
size_t message_len = length;
|
|
||||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
|
||||||
|
|
||||||
auto cb = m_message_callbacks.find(opcode);
|
|
||||||
if (cb != m_message_callbacks.end()) {
|
|
||||||
cb->second(opcode, packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_message_callback) {
|
|
||||||
m_message_callback(opcode, packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
size_t message_len = length;
|
size_t message_len = length;
|
||||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||||
|
|
||||||
@ -319,7 +207,6 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
|||||||
if (m_message_callback) {
|
if (m_message_callback) {
|
||||||
m_message_callback(opcode, packet);
|
m_message_callback(opcode, packet);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
@ -327,54 +214,11 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkClient::SendHandshake(bool downgrade)
|
void EQ::Net::ServertalkClient::SendHandshake()
|
||||||
{
|
{
|
||||||
EQ::Net::DynamicPacket handshake;
|
EQ::Net::DynamicPacket handshake;
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (m_encrypted) {
|
|
||||||
crypto_box_keypair(m_public_key_ours, m_private_key_ours);
|
|
||||||
randombytes_buf(m_nonce_ours, crypto_box_NONCEBYTES);
|
|
||||||
|
|
||||||
crypto_box_beforenm(m_shared_key, m_public_key_theirs, m_private_key_ours);
|
|
||||||
|
|
||||||
handshake.PutData(0, m_public_key_ours, crypto_box_PUBLICKEYBYTES);
|
|
||||||
handshake.PutData(crypto_box_PUBLICKEYBYTES, m_nonce_ours, crypto_box_NONCEBYTES);
|
|
||||||
|
|
||||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
|
||||||
|
|
||||||
size_t cipher_length = m_identifier.length() + 1 + m_credentials.length() + 1 + crypto_secretbox_MACBYTES;
|
|
||||||
size_t data_length = m_identifier.length() + 1 + m_credentials.length() + 1;
|
|
||||||
|
|
||||||
std::unique_ptr<unsigned char[]> signed_buffer(new unsigned char[cipher_length]);
|
|
||||||
std::unique_ptr<unsigned char[]> data_buffer(new unsigned char[data_length]);
|
|
||||||
|
|
||||||
memset(&data_buffer[0], 0, data_length);
|
|
||||||
memcpy(&data_buffer[0], m_identifier.c_str(), m_identifier.length());
|
|
||||||
memcpy(&data_buffer[1 + m_identifier.length()], m_credentials.c_str(), m_credentials.length());
|
|
||||||
|
|
||||||
crypto_box_easy_afternm(&signed_buffer[0], &data_buffer[0], data_length, m_nonce_ours, m_shared_key);
|
|
||||||
|
|
||||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
|
||||||
|
|
||||||
handshake.PutData(crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, &signed_buffer[0], cipher_length);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
handshake.PutString(0, m_identifier);
|
|
||||||
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
|
||||||
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
handshake.PutString(0, m_identifier);
|
handshake.PutString(0, m_identifier);
|
||||||
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
||||||
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
||||||
#endif
|
InternalSend(ServertalkClientDowngradeSecurityHandshake, handshake);
|
||||||
|
|
||||||
if (downgrade) {
|
|
||||||
InternalSend(ServertalkClientDowngradeSecurityHandshake, handshake);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
InternalSend(ServertalkClientHandshake, handshake);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,9 +4,6 @@
|
|||||||
#include "../event/timer.h"
|
#include "../event/timer.h"
|
||||||
#include "servertalk_common.h"
|
#include "servertalk_common.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
#include <sodium.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace EQ
|
namespace EQ
|
||||||
{
|
{
|
||||||
@ -34,8 +31,7 @@ namespace EQ
|
|||||||
void ProcessReadBuffer();
|
void ProcessReadBuffer();
|
||||||
void ProcessHello(EQ::Net::Packet &p);
|
void ProcessHello(EQ::Net::Packet &p);
|
||||||
void ProcessMessage(EQ::Net::Packet &p);
|
void ProcessMessage(EQ::Net::Packet &p);
|
||||||
void SendHandshake() { SendHandshake(false); }
|
void SendHandshake();
|
||||||
void SendHandshake(bool downgrade);
|
|
||||||
|
|
||||||
std::unique_ptr<EQ::Timer> m_timer;
|
std::unique_ptr<EQ::Timer> m_timer;
|
||||||
|
|
||||||
@ -45,23 +41,11 @@ namespace EQ
|
|||||||
bool m_connecting;
|
bool m_connecting;
|
||||||
int m_port;
|
int m_port;
|
||||||
bool m_ipv6;
|
bool m_ipv6;
|
||||||
bool m_encrypted;
|
|
||||||
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
||||||
std::vector<char> m_buffer;
|
std::vector<char> m_buffer;
|
||||||
std::unordered_map<uint16_t, std::function<void(uint16_t, EQ::Net::Packet&)>> m_message_callbacks;
|
std::unordered_map<uint16_t, std::function<void(uint16_t, EQ::Net::Packet&)>> m_message_callbacks;
|
||||||
std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
|
std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
|
||||||
std::function<void(ServertalkClient*)> m_on_connect_cb;
|
std::function<void(ServertalkClient*)> m_on_connect_cb;
|
||||||
|
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
|
||||||
unsigned char m_private_key_ours[crypto_box_SECRETKEYBYTES];
|
|
||||||
unsigned char m_nonce_ours[crypto_box_NONCEBYTES];
|
|
||||||
|
|
||||||
unsigned char m_public_key_theirs[crypto_box_PUBLICKEYBYTES];
|
|
||||||
unsigned char m_nonce_theirs[crypto_box_NONCEBYTES];
|
|
||||||
|
|
||||||
unsigned char m_shared_key[crypto_box_BEFORENMBYTES];
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,4 +15,4 @@ namespace EQ
|
|||||||
ServertalkMessage,
|
ServertalkMessage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,12 +10,10 @@ EQ::Net::ServertalkServer::~ServertalkServer()
|
|||||||
|
|
||||||
void EQ::Net::ServertalkServer::Listen(const ServertalkServerOptions& opts)
|
void EQ::Net::ServertalkServer::Listen(const ServertalkServerOptions& opts)
|
||||||
{
|
{
|
||||||
m_encrypted = opts.encrypted;
|
|
||||||
m_credentials = opts.credentials;
|
m_credentials = opts.credentials;
|
||||||
m_allow_downgrade = opts.allow_downgrade;
|
|
||||||
m_server = std::make_unique<EQ::Net::TCPServer>();
|
m_server = std::make_unique<EQ::Net::TCPServer>();
|
||||||
m_server->Listen(opts.port, opts.ipv6, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
|
m_server->Listen(opts.port, opts.ipv6, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
|
||||||
m_unident_connections.push_back(std::make_shared<ServertalkServerConnection>(connection, this, m_encrypted, m_allow_downgrade));
|
m_unident_connections.push_back(std::make_shared<ServertalkServerConnection>(connection, this));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,10 +5,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
#include <sodium.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace EQ
|
namespace EQ
|
||||||
{
|
{
|
||||||
namespace Net
|
namespace Net
|
||||||
@ -17,18 +13,9 @@ namespace EQ
|
|||||||
{
|
{
|
||||||
int port;
|
int port;
|
||||||
bool ipv6;
|
bool ipv6;
|
||||||
bool encrypted;
|
|
||||||
bool allow_downgrade;
|
|
||||||
std::string credentials;
|
std::string credentials;
|
||||||
|
|
||||||
ServertalkServerOptions() {
|
ServertalkServerOptions() {
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
encrypted = true;
|
|
||||||
allow_downgrade = true;
|
|
||||||
#else
|
|
||||||
encrypted = false;
|
|
||||||
allow_downgrade = true;
|
|
||||||
#endif
|
|
||||||
ipv6 = false;
|
ipv6 = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,12 +3,10 @@
|
|||||||
#include "../eqemu_logsys.h"
|
#include "../eqemu_logsys.h"
|
||||||
#include "../util/uuid.h"
|
#include "../util/uuid.h"
|
||||||
|
|
||||||
EQ::Net::ServertalkServerConnection::ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, EQ::Net::ServertalkServer *parent, bool encrypted, bool allow_downgrade)
|
EQ::Net::ServertalkServerConnection::ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, EQ::Net::ServertalkServer *parent)
|
||||||
{
|
{
|
||||||
m_connection = c;
|
m_connection = c;
|
||||||
m_parent = parent;
|
m_parent = parent;
|
||||||
m_encrypted = encrypted;
|
|
||||||
m_allow_downgrade = allow_downgrade;
|
|
||||||
m_uuid = EQ::Util::UUID::Generate().ToString();
|
m_uuid = EQ::Util::UUID::Generate().ToString();
|
||||||
m_connection->OnRead(std::bind(&ServertalkServerConnection::OnRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
m_connection->OnRead(std::bind(&ServertalkServerConnection::OnRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||||
m_connection->OnDisconnect(std::bind(&ServertalkServerConnection::OnDisconnect, this, std::placeholders::_1));
|
m_connection->OnDisconnect(std::bind(&ServertalkServerConnection::OnDisconnect, this, std::placeholders::_1));
|
||||||
@ -22,30 +20,10 @@ EQ::Net::ServertalkServerConnection::~ServertalkServerConnection()
|
|||||||
void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet & p)
|
void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet & p)
|
||||||
{
|
{
|
||||||
EQ::Net::DynamicPacket out;
|
EQ::Net::DynamicPacket out;
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (m_encrypted) {
|
|
||||||
if (p.Length() == 0) {
|
|
||||||
p.PutUInt8(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
out.PutUInt32(0, p.Length() + crypto_secretbox_MACBYTES);
|
|
||||||
out.PutUInt16(4, opcode);
|
|
||||||
|
|
||||||
std::unique_ptr<unsigned char[]> cipher(new unsigned char[p.Length() + crypto_secretbox_MACBYTES]);
|
|
||||||
crypto_box_easy_afternm(&cipher[0], (unsigned char*)p.Data(), p.Length(), m_nonce_ours, m_shared_key);
|
|
||||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
|
||||||
out.PutData(6, &cipher[0], p.Length() + crypto_secretbox_MACBYTES);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.PutUInt32(0, p.Length());
|
|
||||||
out.PutUInt16(4, opcode);
|
|
||||||
out.PutPacket(6, p);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
out.PutUInt32(0, p.Length());
|
out.PutUInt32(0, p.Length());
|
||||||
out.PutUInt16(4, opcode);
|
out.PutUInt16(4, opcode);
|
||||||
out.PutPacket(6, p);
|
out.PutPacket(6, p);
|
||||||
#endif
|
|
||||||
InternalSend(ServertalkMessage, out);
|
InternalSend(ServertalkMessage, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +87,7 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ServertalkClientHandshake:
|
case ServertalkClientHandshake:
|
||||||
|
case ServertalkClientDowngradeSecurityHandshake:
|
||||||
ProcessHandshake(p);
|
ProcessHandshake(p);
|
||||||
break;
|
break;
|
||||||
case ServertalkMessage:
|
case ServertalkMessage:
|
||||||
@ -125,10 +104,8 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ServertalkClientHandshake:
|
case ServertalkClientHandshake:
|
||||||
ProcessHandshake(p);
|
|
||||||
break;
|
|
||||||
case ServertalkClientDowngradeSecurityHandshake:
|
case ServertalkClientDowngradeSecurityHandshake:
|
||||||
ProcessHandshake(p, true);
|
ProcessHandshake(p);
|
||||||
break;
|
break;
|
||||||
case ServertalkMessage:
|
case ServertalkMessage:
|
||||||
ProcessMessage(p);
|
ProcessMessage(p);
|
||||||
@ -155,29 +132,7 @@ void EQ::Net::ServertalkServerConnection::OnDisconnect(TCPConnection *c)
|
|||||||
void EQ::Net::ServertalkServerConnection::SendHello()
|
void EQ::Net::ServertalkServerConnection::SendHello()
|
||||||
{
|
{
|
||||||
EQ::Net::DynamicPacket hello;
|
EQ::Net::DynamicPacket hello;
|
||||||
|
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
|
||||||
memset(m_nonce_ours, 0, crypto_box_NONCEBYTES);
|
|
||||||
memset(m_nonce_theirs, 0, crypto_box_NONCEBYTES);
|
|
||||||
|
|
||||||
if (m_encrypted) {
|
|
||||||
hello.PutInt8(0, 1);
|
|
||||||
|
|
||||||
crypto_box_keypair(m_public_key_ours, m_private_key_ours);
|
|
||||||
randombytes_buf(m_nonce_ours, crypto_box_NONCEBYTES);
|
|
||||||
|
|
||||||
hello.PutData(1, m_public_key_ours, crypto_box_PUBLICKEYBYTES);
|
|
||||||
hello.PutData(1 + crypto_box_PUBLICKEYBYTES, m_nonce_ours, crypto_box_NONCEBYTES);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hello.PutInt8(0, 0);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
hello.PutInt8(0, 0);
|
hello.PutInt8(0, 0);
|
||||||
#endif
|
|
||||||
|
|
||||||
InternalSend(ServertalkServerHello, hello);
|
InternalSend(ServertalkServerHello, hello);
|
||||||
}
|
}
|
||||||
@ -197,71 +152,8 @@ void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type
|
|||||||
m_connection->Write((const char*)out.Data(), out.Length());
|
m_connection->Write((const char*)out.Data(), out.Length());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, bool downgrade_security)
|
void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (downgrade_security && m_allow_downgrade && m_encrypted) {
|
|
||||||
LogF(Logs::General, Logs::TCPConnection, "Downgraded encrypted connection to plaintext because otherside didn't support encryption {0}:{1}",
|
|
||||||
m_connection->RemoteIP(), m_connection->RemotePort());
|
|
||||||
m_encrypted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_encrypted) {
|
|
||||||
try {
|
|
||||||
if (p.Length() > (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)) {
|
|
||||||
memcpy(m_public_key_theirs, (char*)p.Data(), crypto_box_PUBLICKEYBYTES);
|
|
||||||
memcpy(m_nonce_theirs, (char*)p.Data() + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);
|
|
||||||
|
|
||||||
crypto_box_beforenm(m_shared_key, m_public_key_theirs, m_private_key_ours);
|
|
||||||
|
|
||||||
size_t cipher_len = p.Length() - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES;
|
|
||||||
size_t message_len = cipher_len - crypto_secretbox_MACBYTES;
|
|
||||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
|
||||||
|
|
||||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)p.Data() + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, cipher_len, m_nonce_theirs, m_shared_key))
|
|
||||||
{
|
|
||||||
LogError("Error decrypting handshake from client, dropping connection.");
|
|
||||||
m_connection->Disconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_identifier = (const char*)&decrypted_text[0];
|
|
||||||
std::string credentials = (const char*)&decrypted_text[0] + (m_identifier.length() + 1);
|
|
||||||
|
|
||||||
if (!m_parent->CheckCredentials(credentials)) {
|
|
||||||
LogError("Got incoming connection with invalid credentials during handshake, dropping connection.");
|
|
||||||
m_connection->Disconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_parent->ConnectionIdentified(this);
|
|
||||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (std::exception &ex) {
|
|
||||||
LogError("Error parsing handshake from client: {0}", ex.what());
|
|
||||||
m_connection->Disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
m_identifier = p.GetCString(0);
|
|
||||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
|
||||||
|
|
||||||
if (!m_parent->CheckCredentials(credentials)) {
|
|
||||||
LogError("Got incoming connection with invalid credentials during handshake, dropping connection.");
|
|
||||||
m_connection->Disconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_parent->ConnectionIdentified(this);
|
|
||||||
}
|
|
||||||
catch (std::exception &ex) {
|
|
||||||
LogError("Error parsing handshake from client: {0}", ex.what());
|
|
||||||
m_connection->Disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
try {
|
try {
|
||||||
m_identifier = p.GetCString(0);
|
m_identifier = p.GetCString(0);
|
||||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
auto credentials = p.GetCString(m_identifier.length() + 1);
|
||||||
@ -278,7 +170,6 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
|||||||
LogError("Error parsing handshake from client: {0}", ex.what());
|
LogError("Error parsing handshake from client: {0}", ex.what());
|
||||||
m_connection->Disconnect();
|
m_connection->Disconnect();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||||
@ -288,46 +179,6 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
|||||||
auto opcode = p.GetUInt16(4);
|
auto opcode = p.GetUInt16(4);
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
auto data = p.GetString(6, length);
|
auto data = p.GetString(6, length);
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (m_encrypted) {
|
|
||||||
size_t message_len = length - crypto_secretbox_MACBYTES;
|
|
||||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
|
||||||
|
|
||||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
|
|
||||||
{
|
|
||||||
LogError("Error decrypting message from client");
|
|
||||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EQ::Net::StaticPacket decrypted_packet(&decrypted_text[0], message_len);
|
|
||||||
|
|
||||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
|
||||||
|
|
||||||
auto cb = m_message_callbacks.find(opcode);
|
|
||||||
if (cb != m_message_callbacks.end()) {
|
|
||||||
cb->second(opcode, decrypted_packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_message_callback) {
|
|
||||||
m_message_callback(opcode, decrypted_packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
size_t message_len = length;
|
|
||||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
|
||||||
|
|
||||||
auto cb = m_message_callbacks.find(opcode);
|
|
||||||
if (cb != m_message_callbacks.end()) {
|
|
||||||
cb->second(opcode, packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_message_callback) {
|
|
||||||
m_message_callback(opcode, packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
size_t message_len = length;
|
size_t message_len = length;
|
||||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||||
|
|
||||||
@ -339,7 +190,6 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
|||||||
if (m_message_callback) {
|
if (m_message_callback) {
|
||||||
m_message_callback(opcode, packet);
|
m_message_callback(opcode, packet);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
|
|||||||
@ -4,9 +4,6 @@
|
|||||||
#include "servertalk_common.h"
|
#include "servertalk_common.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
#include <sodium.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace EQ
|
namespace EQ
|
||||||
{
|
{
|
||||||
@ -16,7 +13,7 @@ namespace EQ
|
|||||||
class ServertalkServerConnection
|
class ServertalkServerConnection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, ServertalkServer *parent, bool encrypted, bool allow_downgrade);
|
ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, ServertalkServer *parent);
|
||||||
~ServertalkServerConnection();
|
~ServertalkServerConnection();
|
||||||
|
|
||||||
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
||||||
@ -33,8 +30,7 @@ namespace EQ
|
|||||||
void OnDisconnect(TCPConnection* c);
|
void OnDisconnect(TCPConnection* c);
|
||||||
void SendHello();
|
void SendHello();
|
||||||
void InternalSend(ServertalkPacketType type, EQ::Net::Packet &p);
|
void InternalSend(ServertalkPacketType type, EQ::Net::Packet &p);
|
||||||
void ProcessHandshake(EQ::Net::Packet &p) { ProcessHandshake(p, false); }
|
void ProcessHandshake(EQ::Net::Packet &p);
|
||||||
void ProcessHandshake(EQ::Net::Packet &p, bool security_downgrade);
|
|
||||||
void ProcessMessage(EQ::Net::Packet &p);
|
void ProcessMessage(EQ::Net::Packet &p);
|
||||||
|
|
||||||
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
||||||
@ -45,19 +41,6 @@ namespace EQ
|
|||||||
std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
|
std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
|
||||||
std::string m_identifier;
|
std::string m_identifier;
|
||||||
std::string m_uuid;
|
std::string m_uuid;
|
||||||
|
|
||||||
bool m_encrypted;
|
|
||||||
bool m_allow_downgrade;
|
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
|
||||||
unsigned char m_private_key_ours[crypto_box_SECRETKEYBYTES];
|
|
||||||
unsigned char m_nonce_ours[crypto_box_NONCEBYTES];
|
|
||||||
|
|
||||||
unsigned char m_public_key_theirs[crypto_box_PUBLICKEYBYTES];
|
|
||||||
unsigned char m_nonce_theirs[crypto_box_NONCEBYTES];
|
|
||||||
|
|
||||||
unsigned char m_shared_key[crypto_box_BEFORENMBYTES];
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user