mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 12:41:30 +00:00
Servertalk implementation wip, added optional support for pub-key authenticated encryption (via libsodium), not backwards compatible.
This commit is contained in:
parent
e29ca88a76
commit
1d1df3bf7a
@ -64,10 +64,26 @@ IF(MSVC)
|
||||
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64")
|
||||
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x64")
|
||||
SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x64")
|
||||
SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
|
||||
IF(MSVC_VERSION GREATER 1800)
|
||||
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v140/dynamic")
|
||||
ELSEIF(MSVC_VERSION EQUAL 1800)
|
||||
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v120/dynamic")
|
||||
ELSE()
|
||||
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v110/dynamic")
|
||||
ENDIF()
|
||||
ELSE(CMAKE_CL_64)
|
||||
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86")
|
||||
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86")
|
||||
SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x86")
|
||||
SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
|
||||
IF(MSVC_VERSION GREATER 1800)
|
||||
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v140/dynamic")
|
||||
ELSEIF(MSVC_VERSION EQUAL 1800)
|
||||
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v120/dynamic")
|
||||
ELSE()
|
||||
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v110/dynamic")
|
||||
ENDIF()
|
||||
ENDIF(CMAKE_CL_64)
|
||||
|
||||
#disable CRT warnings on windows cause they're annoying as shit and we use C functions everywhere
|
||||
@ -315,6 +331,26 @@ IF(EQEMU_BUILD_PERL)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${PERL_INCLUDE_PATH}")
|
||||
ENDIF(EQEMU_BUILD_PERL)
|
||||
|
||||
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt)
|
||||
|
||||
FIND_PACKAGE(Sodium REQUIRED)
|
||||
IF(SODIUM_FOUND)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${SODIUM_INCLUDE_DIRS}")
|
||||
ADD_DEFINITIONS(-DENABLE_SECURITY)
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} ${SODIUM_LIBRARIES})
|
||||
ENDIF()
|
||||
|
||||
IF(WIN32)
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} "ws2_32" "psapi" "iphlpapi" "userenv")
|
||||
ENDIF()
|
||||
|
||||
IF(UNIX)
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} ${CMAKE_DL_LIBS} "z" "m" "pthread")
|
||||
IF(NOT DARWIN)
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} "rt")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(EQEMU_BUILD_LUA)
|
||||
FIND_PACKAGE(EQLua51 REQUIRED)
|
||||
SET(Boost_USE_STATIC_LIBS OFF)
|
||||
|
||||
@ -11,26 +11,6 @@ ADD_EXECUTABLE(export_client_files ${export_sources} ${export_headers})
|
||||
|
||||
INSTALL(TARGETS export_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(export_client_files common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY})
|
||||
|
||||
IF(MSVC)
|
||||
SET_TARGET_PROPERTIES(export_client_files PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF")
|
||||
TARGET_LINK_LIBRARIES(export_client_files "Ws2_32.lib")
|
||||
ENDIF(MSVC)
|
||||
|
||||
IF(MINGW)
|
||||
TARGET_LINK_LIBRARIES(export_client_files "WS2_32")
|
||||
ENDIF(MINGW)
|
||||
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(export_client_files "${CMAKE_DL_LIBS}")
|
||||
TARGET_LINK_LIBRARIES(export_client_files "z")
|
||||
TARGET_LINK_LIBRARIES(export_client_files "m")
|
||||
IF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(export_client_files "rt")
|
||||
ENDIF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(export_client_files "pthread")
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ENDIF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(export_client_files ${SERVER_LIBS})
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
@ -11,26 +11,6 @@ ADD_EXECUTABLE(import_client_files ${import_sources} ${import_headers})
|
||||
|
||||
INSTALL(TARGETS import_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(import_client_files common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY})
|
||||
|
||||
IF(MSVC)
|
||||
SET_TARGET_PROPERTIES(import_client_files PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF")
|
||||
TARGET_LINK_LIBRARIES(import_client_files "Ws2_32.lib")
|
||||
ENDIF(MSVC)
|
||||
|
||||
IF(MINGW)
|
||||
TARGET_LINK_LIBRARIES(import_client_files "WS2_32")
|
||||
ENDIF(MINGW)
|
||||
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(import_client_files "${CMAKE_DL_LIBS}")
|
||||
TARGET_LINK_LIBRARIES(import_client_files "z")
|
||||
TARGET_LINK_LIBRARIES(import_client_files "m")
|
||||
IF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(import_client_files "rt")
|
||||
ENDIF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(import_client_files "pthread")
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ENDIF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(import_client_files ${SERVER_LIBS})
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
30
cmake/FindSodium.cmake
Normal file
30
cmake/FindSodium.cmake
Normal file
@ -0,0 +1,30 @@
|
||||
if (NOT MSVC)
|
||||
include(FindPkgConfig)
|
||||
pkg_check_modules(PC_SODIUM "libsodium")
|
||||
if (NOT PC_SODIUM_FOUND)
|
||||
pkg_check_modules(PC_SODIUM "sodium")
|
||||
endif (NOT PC_SODIUM_FOUND)
|
||||
if (PC_SODIUM_FOUND)
|
||||
set(SODIUM_INCLUDE_HINTS ${PC_SODIUM_INCLUDE_DIRS} ${PC_SODIUM_INCLUDE_DIRS}/*)
|
||||
set(SODIUM_LIBRARY_HINTS ${PC_SODIUM_LIBRARY_DIRS} ${PC_SODIUM_LIBRARY_DIRS}/*)
|
||||
endif()
|
||||
endif (NOT MSVC)
|
||||
|
||||
# some libraries install the headers is a subdirectory of the include dir
|
||||
# returned by pkg-config, so use a wildcard match to improve chances of finding
|
||||
# headers and libraries.
|
||||
find_path(
|
||||
SODIUM_INCLUDE_DIRS
|
||||
NAMES sodium.h
|
||||
HINTS ${SODIUM_INCLUDE_HINTS}
|
||||
)
|
||||
|
||||
find_library(
|
||||
SODIUM_LIBRARIES
|
||||
NAMES libsodium sodium
|
||||
HINTS ${SODIUM_LIBRARY_HINTS}
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(SODIUM DEFAULT_MSG SODIUM_LIBRARIES SODIUM_INCLUDE_DIRS)
|
||||
mark_as_advanced(SODIUM_FOUND SODIUM_LIBRARIES SODIUM_INCLUDE_DIRS)
|
||||
@ -76,8 +76,9 @@ SET(common_sources
|
||||
net/daybreak_connection.cpp
|
||||
net/eqstream.cpp
|
||||
net/packet.cpp
|
||||
net/relay.cpp
|
||||
net/relay_link.cpp
|
||||
net/servertalk_client_connection.cpp
|
||||
net/servertalk_server.cpp
|
||||
net/servertalk_server_connection.cpp
|
||||
net/tcp_connection.cpp
|
||||
net/tcp_server.cpp
|
||||
patches/patches.cpp
|
||||
@ -222,8 +223,10 @@ SET(common_headers
|
||||
net/endian.h
|
||||
net/eqstream.h
|
||||
net/packet.h
|
||||
net/relay.h
|
||||
net/relay_link.h
|
||||
net/servertalk_client_connection.h
|
||||
net/servertalk_common.h
|
||||
net/servertalk_server.h
|
||||
net/servertalk_server_connection.h
|
||||
net/tcp_connection.h
|
||||
net/tcp_server.h
|
||||
patches/patches.h
|
||||
@ -301,10 +304,13 @@ SOURCE_GROUP(Net FILES
|
||||
net/eqstream.h
|
||||
net/packet.cpp
|
||||
net/packet.h
|
||||
net/relay.cpp
|
||||
net/relay.h
|
||||
net/relay_link.cpp
|
||||
net/relay_link.h
|
||||
net/servertalk_client_connection.cpp
|
||||
net/servertalk_client_connection.h
|
||||
net/servertalk_common.h
|
||||
net/servertalk_server.cpp
|
||||
net/servertalk_server.h
|
||||
net/servertalk_server_connection.cpp
|
||||
net/servertalk_server_connection.h
|
||||
net/tcp_connection.cpp
|
||||
net/tcp_connection.h
|
||||
net/tcp_server.cpp
|
||||
@ -414,7 +420,6 @@ INCLUDE_DIRECTORIES(Patches SocketLib StackWalker TinyXML)
|
||||
ADD_LIBRARY(common ${common_sources} ${common_headers})
|
||||
|
||||
IF(UNIX)
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
SET_SOURCE_FILES_PROPERTIES("SocketLib/Mime.cpp" PROPERTY COMPILE_FLAGS -Wno-unused-result)
|
||||
SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0)
|
||||
ENDIF(UNIX)
|
||||
|
||||
@ -1,236 +0,0 @@
|
||||
#include "relay_link.h"
|
||||
#include "dns.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../md5.h"
|
||||
#include "../servertalk.h"
|
||||
|
||||
EQ::Net::RelayLink::RelayLink(const std::string &addr, int port, const std::string &identifier, const std::string &password)
|
||||
: m_timer(std::unique_ptr<EQ::Timer>(new EQ::Timer(250, true, std::bind(&EQ::Net::RelayLink::Connect, this)))),
|
||||
m_keepalive(std::unique_ptr<EQ::Timer>(new EQ::Timer(5000, true, std::bind(&EQ::Net::RelayLink::SendKeepAlive, this))))
|
||||
{
|
||||
m_established = false;
|
||||
m_connecting = false;
|
||||
m_port = port;
|
||||
m_identifier = identifier;
|
||||
m_password = password;
|
||||
DNSLookup(addr, port, false, [this](const std::string &address) {
|
||||
m_addr = address;
|
||||
});
|
||||
|
||||
m_opcode_dispatch.insert(std::make_pair(ServerOP_ZAAuthFailed, std::bind(&RelayLink::OnAuthFailed, this, std::placeholders::_1)));
|
||||
}
|
||||
|
||||
EQ::Net::RelayLink::~RelayLink()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::OnMessageType(uint16 opcode, std::function<void(const EQ::Net::Packet&p)> cb)
|
||||
{
|
||||
if (opcode != ServerOP_ZAAuthFailed) {
|
||||
m_opcode_dispatch.insert(std::make_pair(opcode, cb));
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::SendPacket(uint16 opcode, const EQ::Net::Packet &p)
|
||||
{
|
||||
EQ::Net::WritablePacket packet;
|
||||
packet.PutUInt32(0, p.Length() + 7);
|
||||
packet.PutInt8(4, 0);
|
||||
packet.PutUInt16(5, opcode);
|
||||
if(p.Length() > 0)
|
||||
packet.PutPacket(7, p);
|
||||
|
||||
if (m_connection) {
|
||||
m_connection->Write((const char*)packet.Data(), packet.Length());
|
||||
}
|
||||
else {
|
||||
m_packet_queue.push(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::Connect()
|
||||
{
|
||||
if (m_addr.length() == 0 || m_port == 0 || m_connection || m_connecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_connecting = true;
|
||||
EQ::Net::TCPConnection::Connect(m_addr, m_port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
|
||||
if (connection == nullptr) {
|
||||
Log.OutF(Logs::General, Logs::Debug, "Error connecting to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
m_connecting = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Log.OutF(Logs::General, Logs::Debug, "Connected to {0}:{1}", m_addr, m_port);
|
||||
m_connection = connection;
|
||||
m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) {
|
||||
Log.OutF(Logs::General, Logs::Debug, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
m_established = false;
|
||||
m_connection.reset();
|
||||
});
|
||||
|
||||
m_connection->OnRead(std::bind(&EQ::Net::RelayLink::ProcessData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
m_connection->Start();
|
||||
|
||||
SendIdentifier();
|
||||
m_connecting = false;
|
||||
});
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length)
|
||||
{
|
||||
EQ::Net::ReadOnlyPacket p((void*)data, length);
|
||||
try {
|
||||
Log.OutF(Logs::General, Logs::Debug, "Process data:\n{0}", p.ToString());
|
||||
|
||||
if (m_established) {
|
||||
ProcessPacket(p);
|
||||
}
|
||||
else {
|
||||
std::string msg;
|
||||
if (m_identifier.compare("LOGIN") == 0) {
|
||||
msg = fmt::format("**PACKETMODE**\r");
|
||||
}
|
||||
else {
|
||||
msg = fmt::format("**PACKETMODE{0}**\r", m_identifier);
|
||||
}
|
||||
|
||||
std::string cmp_msg;
|
||||
if (p.GetInt8(0) == '*') {
|
||||
cmp_msg = p.GetString(0, msg.length());
|
||||
}
|
||||
else if (p.GetInt8(1) == '*') {
|
||||
cmp_msg = p.GetString(1, msg.length());
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmp_msg.compare(msg) == 0) {
|
||||
m_established = true;
|
||||
Log.OutF(Logs::General, Logs::Debug, "Established connection of type {0}", m_identifier);
|
||||
SendPassword();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
Log.OutF(Logs::General, Logs::Debug, "Error parsing relay link packet: {0}", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::ProcessPacket(const EQ::Net::Packet &p)
|
||||
{
|
||||
char *buffer = (char*)p.Data();
|
||||
m_data_buffer.insert(m_data_buffer.begin() + m_data_buffer.size(), buffer, buffer + p.Length());
|
||||
|
||||
ProcessBuffer();
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::ProcessBuffer()
|
||||
{
|
||||
size_t size = 7;
|
||||
size_t base = 0;
|
||||
size_t used = m_data_buffer.size();
|
||||
while ((used - base) >= size) {
|
||||
uint32 packet_size = *(uint32*)&m_data_buffer[base];
|
||||
uint8 packet_flags = *(uint8*)&m_data_buffer[base + 4];
|
||||
uint16 packet_opcode = *(uint16*)&m_data_buffer[base + 5];
|
||||
|
||||
if ((used - base) >= packet_size) {
|
||||
EQ::Net::ReadOnlyPacket p(&m_data_buffer[base], packet_size);
|
||||
|
||||
if (m_opcode_dispatch.count(packet_opcode) > 0) {
|
||||
auto &cb = m_opcode_dispatch[(int)packet_opcode];
|
||||
cb(p);
|
||||
}
|
||||
else {
|
||||
Log.OutF(Logs::General, Logs::Debug, "Unhandled packet of type {0:x}", packet_opcode);
|
||||
}
|
||||
|
||||
base += packet_size;
|
||||
}
|
||||
else {
|
||||
EQ::Net::WritablePacket p;
|
||||
|
||||
if (m_opcode_dispatch.count(packet_opcode) > 0) {
|
||||
auto &cb = m_opcode_dispatch[(int)packet_opcode];
|
||||
cb(p);
|
||||
}
|
||||
else {
|
||||
Log.OutF(Logs::General, Logs::Debug, "Unhandled packet of type {0:x}", packet_opcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (used == base) {
|
||||
m_data_buffer.clear();
|
||||
}
|
||||
else {
|
||||
m_data_buffer.erase(m_data_buffer.begin(), m_data_buffer.begin() + base);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::ProcessQueue()
|
||||
{
|
||||
if (!m_connection)
|
||||
return;
|
||||
|
||||
while (!m_packet_queue.empty()) {
|
||||
auto &p = m_packet_queue.front();
|
||||
m_connection->Write((const char*)p.Data(), p.Length());
|
||||
m_packet_queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::SendIdentifier()
|
||||
{
|
||||
std::string msg;
|
||||
if (m_identifier.compare("LOGIN") == 0) {
|
||||
msg = fmt::format("**PACKETMODE**\r");
|
||||
}
|
||||
else {
|
||||
msg = fmt::format("**PACKETMODE{0}**\r", m_identifier);
|
||||
}
|
||||
EQ::Net::WritablePacket packet;
|
||||
packet.PutData(0, (void*)msg.c_str(), msg.length());
|
||||
SendInternal(packet);
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::SendInternal(const EQ::Net::Packet &p)
|
||||
{
|
||||
if (m_connection == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_connection->Write((const char*)p.Data(), p.Length());
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::SendPassword()
|
||||
{
|
||||
if (m_password.length() > 0) {
|
||||
char hash[16] = { 0 };
|
||||
MD5::Generate((const uchar*)m_password.c_str(), m_password.length(), (uchar*)&hash[0]);
|
||||
|
||||
EQ::Net::WritablePacket p;
|
||||
p.PutData(0, &hash[0], 16);
|
||||
SendPacket(ServerOP_ZAAuth, p);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::OnAuthFailed(const EQ::Net::Packet &p)
|
||||
{
|
||||
if (m_connection) {
|
||||
Log.OutF(Logs::General, Logs::Debug, "Authorization failed for server type {0}", m_identifier);
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::RelayLink::SendKeepAlive()
|
||||
{
|
||||
if (!m_connection)
|
||||
return;
|
||||
|
||||
EQ::Net::WritablePacket p;
|
||||
SendPacket(0, p);
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "tcp_server.h"
|
||||
#include "packet.h"
|
||||
#include "../types.h"
|
||||
#include "../event/timer.h"
|
||||
#include "../event/event_loop.h"
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net {
|
||||
class RelayLink
|
||||
{
|
||||
public:
|
||||
RelayLink(const std::string &addr, int port, const std::string &identifier, const std::string &password);
|
||||
~RelayLink();
|
||||
|
||||
void OnMessageType(uint16 opcode, std::function<void(const EQ::Net::Packet &p)> cb);
|
||||
void SendPacket(uint16 opcode, const EQ::Net::Packet &p);
|
||||
bool Connected() const { return m_connection != nullptr; }
|
||||
std::string GetIP() const { return m_addr; }
|
||||
uint16 GetPort() const { return m_port; }
|
||||
private:
|
||||
void Connect();
|
||||
void ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length);
|
||||
void ProcessPacket(const EQ::Net::Packet &p);
|
||||
void ProcessBuffer();
|
||||
void ProcessQueue();
|
||||
void SendIdentifier();
|
||||
void SendInternal(const EQ::Net::Packet &p);
|
||||
void SendPassword();
|
||||
void OnAuthFailed(const EQ::Net::Packet &p);
|
||||
void SendKeepAlive();
|
||||
|
||||
std::unique_ptr<EQ::Timer> m_timer;
|
||||
std::unique_ptr<EQ::Timer> m_keepalive;
|
||||
std::string m_addr;
|
||||
std::string m_identifier;
|
||||
std::string m_password;
|
||||
int m_port;
|
||||
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
||||
bool m_established;
|
||||
bool m_connecting;
|
||||
std::vector<char> m_data_buffer;
|
||||
std::map<uint16, std::function<void(const EQ::Net::Packet &p)>> m_opcode_dispatch;
|
||||
std::queue<EQ::Net::WritablePacket> m_packet_queue;
|
||||
};
|
||||
}
|
||||
}
|
||||
235
common/net/servertalk_client_connection.cpp
Normal file
235
common/net/servertalk_client_connection.cpp
Normal file
@ -0,0 +1,235 @@
|
||||
#include "servertalk_client_connection.h"
|
||||
#include "dns.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
|
||||
EQ::Net::ServertalkClient::ServertalkClient(const std::string &addr, int port, bool ipv6, const std::string &identifier, const std::string &credentials)
|
||||
: m_timer(std::unique_ptr<EQ::Timer>(new EQ::Timer(100, true, std::bind(&EQ::Net::ServertalkClient::Connect, this))))
|
||||
{
|
||||
m_port = port;
|
||||
m_ipv6 = ipv6;
|
||||
m_identifier = identifier.empty() ? "Unknown" : identifier;
|
||||
m_credentials = credentials;
|
||||
m_connecting = false;
|
||||
DNSLookup(addr, port, false, [this](const std::string &address) {
|
||||
m_addr = address;
|
||||
});
|
||||
}
|
||||
|
||||
EQ::Net::ServertalkClient::~ServertalkClient()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::Connect()
|
||||
{
|
||||
if (m_addr.length() == 0 || m_port == 0 || m_connection || m_connecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_connecting = true;
|
||||
EQ::Net::TCPConnection::Connect(m_addr, m_port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
|
||||
if (connection == nullptr) {
|
||||
Log.OutF(Logs::General, Logs::TCP_Connection, "Error connecting to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
m_connecting = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Log.OutF(Logs::General, Logs::TCP_Connection, "Connected to {0}:{1}", m_addr, m_port);
|
||||
m_connection = connection;
|
||||
m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) {
|
||||
Log.OutF(Logs::General, Logs::TCP_Connection, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
m_connection.reset();
|
||||
m_encrypted = false;
|
||||
});
|
||||
|
||||
m_connection->OnRead(std::bind(&EQ::Net::ServertalkClient::ProcessData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
m_connection->Start();
|
||||
|
||||
SendHello();
|
||||
m_connecting = false;
|
||||
});
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length)
|
||||
{
|
||||
m_buffer.insert(m_buffer.end(), (const char*)data, (const char*)data + length);
|
||||
ProcessReadBuffer();
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::SendHello()
|
||||
{
|
||||
EQ::Net::WritablePacket p;
|
||||
InternalSend(ServertalkClientHello, p);
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::InternalSend(ServertalkPacketType type, EQ::Net::Packet &p)
|
||||
{
|
||||
if (!m_connection)
|
||||
return;
|
||||
|
||||
EQ::Net::WritablePacket out;
|
||||
out.PutUInt32(0, (uint32_t)p.Length());
|
||||
out.PutUInt8(4, (uint8_t)type);
|
||||
if (p.Length() > 0) {
|
||||
out.PutPacket(5, p);
|
||||
}
|
||||
|
||||
m_connection->Write((const char*)out.Data(), out.Length());
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::ProcessReadBuffer()
|
||||
{
|
||||
size_t current = 0;
|
||||
size_t total = m_buffer.size();
|
||||
|
||||
while (current < total) {
|
||||
auto left = total - current;
|
||||
|
||||
/*
|
||||
//header:
|
||||
//uint32 length;
|
||||
//uint8 type;
|
||||
*/
|
||||
size_t length = 0;
|
||||
uint8_t type = 0;
|
||||
if (left < 5) {
|
||||
break;
|
||||
}
|
||||
|
||||
length = *(uint32_t*)&m_buffer[current];
|
||||
type = *(uint8_t*)&m_buffer[current + 4];
|
||||
|
||||
if (current + 5 + length < total) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
EQ::Net::WritablePacket p;
|
||||
switch (type) {
|
||||
case ServertalkServerHello:
|
||||
ProcessHello(p);
|
||||
break;
|
||||
case ServertalkMessage:
|
||||
ProcessMessage(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
EQ::Net::ReadOnlyPacket p(&m_buffer[current + 5], length);
|
||||
switch (type) {
|
||||
case ServertalkServerHello:
|
||||
ProcessHello(p);
|
||||
break;
|
||||
case ServertalkMessage:
|
||||
ProcessMessage(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current += length + 5;
|
||||
}
|
||||
|
||||
if (current == total) {
|
||||
m_buffer.clear();
|
||||
}
|
||||
else {
|
||||
m_buffer.erase(m_buffer.begin(), m_buffer.begin() + current);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
m_encrypted = false;
|
||||
|
||||
try {
|
||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
||||
|
||||
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();
|
||||
}
|
||||
else {
|
||||
Log.OutF(Logs::General, Logs::Error, "Could not process hello, size != {0}", 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SendHandshake();
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
#else
|
||||
try {
|
||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
||||
|
||||
if (enc) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Server requested encryption but we do not support encryption.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
SendHandshake();
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::SendHandshake()
|
||||
{
|
||||
EQ::Net::WritablePacket 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);
|
||||
|
||||
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;
|
||||
unsigned char *signed_buffer = new unsigned char[cipher_length];
|
||||
unsigned char *data_buffer = new unsigned char[data_length];
|
||||
memset(data_buffer, 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, data_buffer, data_length, m_nonce_ours, m_shared_key);
|
||||
|
||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
||||
|
||||
handshake.PutData(crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, signed_buffer, cipher_length);
|
||||
|
||||
Log.OutF(Logs::General, Logs::Debug, "Sending {1} bytes handshake:\n{0}", handshake.ToString(), handshake.Length());
|
||||
|
||||
delete[] signed_buffer;
|
||||
delete[] data_buffer;
|
||||
}
|
||||
else {
|
||||
handshake.PutString(0, m_identifier);
|
||||
}
|
||||
#else
|
||||
handshake.PutString(0, m_identifier);
|
||||
#endif
|
||||
InternalSend(ServertalkClientHandshake, handshake);
|
||||
}
|
||||
53
common/net/servertalk_client_connection.h
Normal file
53
common/net/servertalk_client_connection.h
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "tcp_connection.h"
|
||||
#include "../event/timer.h"
|
||||
#include "servertalk_common.h"
|
||||
#include "packet.h"
|
||||
#include <sodium.h>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
class ServertalkClient
|
||||
{
|
||||
public:
|
||||
ServertalkClient(const std::string &addr, int port, bool ipv6, const std::string &identifier, const std::string &credentials);
|
||||
~ServertalkClient();
|
||||
|
||||
private:
|
||||
void Connect();
|
||||
void ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length);
|
||||
void SendHello();
|
||||
void InternalSend(ServertalkPacketType type, EQ::Net::Packet &p);
|
||||
void ProcessReadBuffer();
|
||||
void ProcessHello(EQ::Net::Packet &p);
|
||||
void ProcessMessage(EQ::Net::Packet &p);
|
||||
void SendHandshake();
|
||||
|
||||
std::unique_ptr<EQ::Timer> m_timer;
|
||||
|
||||
std::string m_addr;
|
||||
std::string m_identifier;
|
||||
std::string m_credentials;
|
||||
bool m_connecting;
|
||||
int m_port;
|
||||
bool m_ipv6;
|
||||
bool m_encrypted;
|
||||
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
||||
std::vector<char> m_buffer;
|
||||
|
||||
#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
common/net/servertalk_common.h
Normal file
15
common/net/servertalk_common.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
enum ServertalkPacketType
|
||||
{
|
||||
ServertalkClientHello = 1,
|
||||
ServertalkServerHello,
|
||||
ServertalkClientHandshake,
|
||||
ServertalkMessage,
|
||||
};
|
||||
}
|
||||
}
|
||||
96
common/net/servertalk_server.cpp
Normal file
96
common/net/servertalk_server.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
#include "servertalk_server.h"
|
||||
|
||||
EQ::Net::ServertalkServer::ServertalkServer()
|
||||
{
|
||||
}
|
||||
|
||||
EQ::Net::ServertalkServer::~ServertalkServer()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::Listen(const ServertalkServerOptions& opts)
|
||||
{
|
||||
m_encrypted = opts.encrypted;
|
||||
m_credentials = opts.credentials;
|
||||
m_server.reset(new EQ::Net::TCPServer());
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::OnConnectionIdentified(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb)
|
||||
{
|
||||
m_on_ident.insert(std::make_pair(type, cb));
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::OnConnectionRemoved(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb)
|
||||
{
|
||||
m_on_disc.insert(std::make_pair(type, cb));
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::ConnectionDisconnected(ServertalkServerConnection *conn)
|
||||
{
|
||||
if (conn->GetIdentifier().empty()) {
|
||||
auto iter = m_unident_connections.begin();
|
||||
while (iter != m_unident_connections.end()) {
|
||||
if (conn == iter->get()) {
|
||||
m_unident_connections.erase(iter);
|
||||
return;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto type = m_ident_connections.find(conn->GetIdentifier());
|
||||
if (type != m_ident_connections.end()) {
|
||||
auto iter = type->second.begin();
|
||||
while (iter != type->second.end()) {
|
||||
if (conn == iter->get()) {
|
||||
auto on_disc = m_on_disc.find(conn->GetIdentifier());
|
||||
if (on_disc != m_on_disc.end()) {
|
||||
on_disc->second(*iter);
|
||||
}
|
||||
type->second.erase(iter);
|
||||
return;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::ConnectionIdentified(ServertalkServerConnection *conn)
|
||||
{
|
||||
auto iter = m_unident_connections.begin();
|
||||
while (iter != m_unident_connections.end()) {
|
||||
if (conn == iter->get()) {
|
||||
auto on_ident = m_on_ident.find(conn->GetIdentifier());
|
||||
if (on_ident != m_on_ident.end()) {
|
||||
on_ident->second(*iter);
|
||||
}
|
||||
|
||||
if (m_ident_connections.count(conn->GetIdentifier()) > 0) {
|
||||
auto &vec = m_ident_connections[conn->GetIdentifier()];
|
||||
vec.push_back(*iter);
|
||||
}
|
||||
else {
|
||||
std::vector<std::shared_ptr<EQ::Net::ServertalkServerConnection>> vec;
|
||||
vec.push_back(*iter);
|
||||
m_ident_connections.insert(std::make_pair(conn->GetIdentifier(), vec));
|
||||
}
|
||||
|
||||
m_unident_connections.erase(iter);
|
||||
return;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
bool EQ::Net::ServertalkServer::CheckCredentials(const std::string &credentials)
|
||||
{
|
||||
if (credentials.compare(m_credentials) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
58
common/net/servertalk_server.h
Normal file
58
common/net/servertalk_server.h
Normal file
@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include "tcp_server.h"
|
||||
#include "servertalk_server_connection.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
struct ServertalkServerOptions
|
||||
{
|
||||
int port;
|
||||
bool ipv6;
|
||||
bool encrypted;
|
||||
std::string credentials;
|
||||
|
||||
ServertalkServerOptions() {
|
||||
#ifdef ENABLE_SECURITY
|
||||
encrypted = true;
|
||||
#endif
|
||||
ipv6 = false;
|
||||
}
|
||||
};
|
||||
|
||||
class ServertalkServer
|
||||
{
|
||||
public:
|
||||
ServertalkServer();
|
||||
~ServertalkServer();
|
||||
|
||||
void Listen(const ServertalkServerOptions& opts);
|
||||
void OnConnectionIdentified(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb);
|
||||
void OnConnectionRemoved(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb);
|
||||
|
||||
private:
|
||||
void ConnectionDisconnected(ServertalkServerConnection *conn);
|
||||
void ConnectionIdentified(ServertalkServerConnection *conn);
|
||||
bool CheckCredentials(const std::string &credentials);
|
||||
|
||||
std::unique_ptr<EQ::Net::TCPServer> m_server;
|
||||
std::vector<std::shared_ptr<ServertalkServerConnection>> m_unident_connections;
|
||||
std::map<std::string, std::vector<std::shared_ptr<ServertalkServerConnection>>> m_ident_connections;
|
||||
|
||||
std::map<std::string, std::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_ident;
|
||||
std::map<std::string, std::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_disc;
|
||||
bool m_encrypted;
|
||||
std::string m_credentials;
|
||||
|
||||
friend class ServertalkServerConnection;
|
||||
};
|
||||
}
|
||||
}
|
||||
196
common/net/servertalk_server_connection.cpp
Normal file
196
common/net/servertalk_server_connection.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
#include "servertalk_server_connection.h"
|
||||
#include "servertalk_server.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
|
||||
EQ::Net::ServertalkServerConnection::ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, EQ::Net::ServertalkServer *parent, bool encrypted)
|
||||
{
|
||||
m_connection = c;
|
||||
m_parent = parent;
|
||||
m_encrypted = encrypted;
|
||||
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->Start();
|
||||
}
|
||||
|
||||
EQ::Net::ServertalkServerConnection::~ServertalkServerConnection()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::OnRead(TCPConnection *c, const unsigned char *data, size_t sz)
|
||||
{
|
||||
m_buffer.insert(m_buffer.end(), (const char*)data, (const char*)data + sz);
|
||||
ProcessReadBuffer();
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
||||
{
|
||||
size_t current = 0;
|
||||
size_t total = m_buffer.size();
|
||||
|
||||
while (current < total) {
|
||||
auto left = total - current;
|
||||
|
||||
/*
|
||||
//header:
|
||||
//uint32 length;
|
||||
//uint8 type;
|
||||
*/
|
||||
size_t length = 0;
|
||||
uint8_t type = 0;
|
||||
if (left < 5) {
|
||||
break;
|
||||
}
|
||||
|
||||
length = *(uint32_t*)&m_buffer[current];
|
||||
type = *(uint8_t*)&m_buffer[current + 4];
|
||||
|
||||
if (current + 5 + length < total) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
EQ::Net::WritablePacket p;
|
||||
switch (type) {
|
||||
case ServertalkClientHello:
|
||||
{
|
||||
SendHello();
|
||||
}
|
||||
break;
|
||||
case ServertalkClientHandshake:
|
||||
ProcessHandshake(p);
|
||||
break;
|
||||
case ServertalkMessage:
|
||||
ProcessMessage(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
EQ::Net::ReadOnlyPacket p(&m_buffer[current + 5], length);
|
||||
switch (type) {
|
||||
case ServertalkClientHello:
|
||||
{
|
||||
SendHello();
|
||||
}
|
||||
break;
|
||||
case ServertalkClientHandshake:
|
||||
ProcessHandshake(p);
|
||||
break;
|
||||
case ServertalkMessage:
|
||||
ProcessMessage(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current += length + 5;
|
||||
}
|
||||
|
||||
if (current == total) {
|
||||
m_buffer.clear();
|
||||
}
|
||||
else {
|
||||
m_buffer.erase(m_buffer.begin(), m_buffer.begin() + current);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::OnDisconnect(TCPConnection *c)
|
||||
{
|
||||
m_parent->ConnectionDisconnected(this);
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::SendHello()
|
||||
{
|
||||
EQ::Net::WritablePacket 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);
|
||||
#endif
|
||||
|
||||
InternalSend(ServertalkServerHello, hello);
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type, EQ::Net::Packet &p)
|
||||
{
|
||||
if (!m_connection)
|
||||
return;
|
||||
|
||||
EQ::Net::WritablePacket out;
|
||||
out.PutUInt32(0, (uint32_t)p.Length());
|
||||
out.PutUInt8(4, (uint8_t)type);
|
||||
if (p.Length() > 0) {
|
||||
out.PutPacket(5, p);
|
||||
}
|
||||
|
||||
m_connection->Write((const char*)out.Data(), out.Length());
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p)
|
||||
{
|
||||
#ifdef ENABLE_SECURITY
|
||||
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;
|
||||
unsigned char *decrypted_text = new unsigned char[message_len];
|
||||
if (crypto_box_open_easy_afternm(decrypted_text, (unsigned char*)p.Data() + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, cipher_len, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
Log.OutF(Logs::General, Logs::Error, "Error decrypting handshake from client, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
m_identifier = (const char*)decrypted_text;
|
||||
std::string credentials = (const char*)decrypted_text + (m_identifier.length() + 1);
|
||||
|
||||
if (!m_parent->CheckCredentials(credentials)) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
m_parent->ConnectionIdentified(this);
|
||||
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
delete[] decrypted_text;
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_identifier.assign((char*)p.Data(), p.Length());
|
||||
}
|
||||
#else
|
||||
m_identifier.assign((char*)p.Data(), p.Length());
|
||||
#endif
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
{
|
||||
}
|
||||
51
common/net/servertalk_server_connection.h
Normal file
51
common/net/servertalk_server_connection.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "tcp_connection.h"
|
||||
#include "servertalk_common.h"
|
||||
#include "packet.h"
|
||||
#include <vector>
|
||||
#include <sodium.h>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
class ServertalkServer;
|
||||
class ServertalkServerConnection
|
||||
{
|
||||
public:
|
||||
ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, ServertalkServer *parent, bool encrypted);
|
||||
~ServertalkServerConnection();
|
||||
|
||||
std::string GetIdentifier() const {
|
||||
return m_identifier;
|
||||
}
|
||||
private:
|
||||
void OnRead(TCPConnection* c, const unsigned char* data, size_t sz);
|
||||
void ProcessReadBuffer();
|
||||
void OnDisconnect(TCPConnection* c);
|
||||
void SendHello();
|
||||
void InternalSend(ServertalkPacketType type, EQ::Net::Packet &p);
|
||||
void ProcessHandshake(EQ::Net::Packet &p);
|
||||
void ProcessMessage(EQ::Net::Packet &p);
|
||||
|
||||
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
||||
ServertalkServer *m_parent;
|
||||
|
||||
std::vector<char> m_buffer;
|
||||
std::string m_identifier;
|
||||
|
||||
bool m_encrypted;
|
||||
#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
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -107,12 +107,17 @@ void EQ::Net::TCPConnection::OnDisconnect(std::function<void(TCPConnection*)> cb
|
||||
void EQ::Net::TCPConnection::Disconnect()
|
||||
{
|
||||
if (m_socket) {
|
||||
uv_close((uv_handle_t*)m_socket, on_close_handle);
|
||||
m_socket->data = this;
|
||||
uv_close((uv_handle_t*)m_socket, [](uv_handle_t* handle) {
|
||||
TCPConnection *connection = (TCPConnection*)handle->data;
|
||||
|
||||
if (connection->m_on_disconnect_cb) {
|
||||
connection->m_on_disconnect_cb(connection);
|
||||
}
|
||||
|
||||
delete handle;
|
||||
});
|
||||
m_socket = nullptr;
|
||||
|
||||
if (m_on_disconnect_cb) {
|
||||
m_on_disconnect_cb(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,26 +15,6 @@ ADD_EXECUTABLE(eqlaunch ${eqlaunch_sources} ${eqlaunch_headers})
|
||||
|
||||
INSTALL(TARGETS eqlaunch RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(eqlaunch common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY})
|
||||
|
||||
IF(MSVC)
|
||||
SET_TARGET_PROPERTIES(eqlaunch PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF")
|
||||
TARGET_LINK_LIBRARIES(eqlaunch "Ws2_32.lib")
|
||||
ENDIF(MSVC)
|
||||
|
||||
IF(MINGW)
|
||||
TARGET_LINK_LIBRARIES(eqlaunch "WS2_32")
|
||||
ENDIF(MINGW)
|
||||
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(eqlaunch "${CMAKE_DL_LIBS}")
|
||||
TARGET_LINK_LIBRARIES(eqlaunch "z")
|
||||
TARGET_LINK_LIBRARIES(eqlaunch "m")
|
||||
IF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(eqlaunch "rt")
|
||||
ENDIF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(eqlaunch "pthread")
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ENDIF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(eqlaunch ${SERVER_LIBS})
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
@ -21,21 +21,6 @@ INSTALL(TARGETS queryserv RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
ADD_DEFINITIONS(-DQSERV)
|
||||
|
||||
TARGET_LINK_LIBRARIES(queryserv common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt)
|
||||
|
||||
IF(WIN32)
|
||||
TARGET_LINK_LIBRARIES(queryserv "ws2_32" "psapi" "iphlpapi" "userenv")
|
||||
ENDIF(WIN32)
|
||||
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(queryserv "${CMAKE_DL_LIBS}")
|
||||
TARGET_LINK_LIBRARIES(queryserv "z")
|
||||
TARGET_LINK_LIBRARIES(queryserv "m")
|
||||
IF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(queryserv "rt")
|
||||
ENDIF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(queryserv "pthread")
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ENDIF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(queryserv ${SERVER_LIBS})
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
@ -23,26 +23,6 @@ ADD_EXECUTABLE(shared_memory ${shared_memory_sources} ${shared_memory_headers})
|
||||
|
||||
INSTALL(TARGETS shared_memory RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(shared_memory common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY})
|
||||
|
||||
IF(MSVC)
|
||||
SET_TARGET_PROPERTIES(shared_memory PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF")
|
||||
TARGET_LINK_LIBRARIES(shared_memory "Ws2_32.lib")
|
||||
ENDIF(MSVC)
|
||||
|
||||
IF(MINGW)
|
||||
TARGET_LINK_LIBRARIES(shared_memory "WS2_32")
|
||||
ENDIF(MINGW)
|
||||
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(shared_memory "${CMAKE_DL_LIBS}")
|
||||
TARGET_LINK_LIBRARIES(shared_memory "z")
|
||||
TARGET_LINK_LIBRARIES(shared_memory "m")
|
||||
IF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(shared_memory "rt")
|
||||
ENDIF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(shared_memory "pthread")
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ENDIF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(shared_memory ${SERVER_LIBS})
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
@ -23,21 +23,6 @@ INSTALL(TARGETS ucs RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
ADD_DEFINITIONS(-DUCS)
|
||||
|
||||
TARGET_LINK_LIBRARIES(ucs common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt)
|
||||
|
||||
IF(WIN32)
|
||||
TARGET_LINK_LIBRARIES(ucs "ws2_32" "psapi" "iphlpapi" "userenv")
|
||||
ENDIF(WIN32)
|
||||
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(ucs "${CMAKE_DL_LIBS}")
|
||||
TARGET_LINK_LIBRARIES(ucs "z")
|
||||
TARGET_LINK_LIBRARIES(ucs "m")
|
||||
IF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(ucs "rt")
|
||||
ENDIF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(ucs "pthread")
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ENDIF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(ucs ${SERVER_LIBS})
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
17
ucs/ucs.cpp
17
ucs/ucs.cpp
@ -34,6 +34,8 @@
|
||||
#include <signal.h>
|
||||
|
||||
#include "../common/net/tcp_server.h"
|
||||
#include "../common/net/servertalk_server.h"
|
||||
#include "../common/net/servertalk_client_connection.h"
|
||||
|
||||
ChatChannelList *ChannelList;
|
||||
Clientlist *g_Clientlist;
|
||||
@ -144,6 +146,21 @@ int main() {
|
||||
|
||||
worldserver->Connect();
|
||||
|
||||
EQ::Net::ServertalkServer server;
|
||||
EQ::Net::ServertalkServerOptions opts;
|
||||
opts.port = 5999;
|
||||
server.Listen(opts);
|
||||
|
||||
server.OnConnectionIdentified("QueryServ", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> conn) {
|
||||
Log.Out(Logs::General, Logs::Debug, "New QueryServ Connection....");
|
||||
});
|
||||
|
||||
server.OnConnectionRemoved("QueryServ", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> conn) {
|
||||
Log.Out(Logs::General, Logs::Debug, "Lost QueryServ connection.");
|
||||
});
|
||||
|
||||
EQ::Net::ServertalkClient client("127.0.0.1", 5999, false, "QueryServ", "User:Root;Password:1234567890");
|
||||
|
||||
while(RunLoops) {
|
||||
|
||||
Timer::SetCurrentTime();
|
||||
|
||||
@ -68,21 +68,10 @@ INSTALL(TARGETS world RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
ADD_DEFINITIONS(-DWORLD)
|
||||
|
||||
TARGET_LINK_LIBRARIES(world common ${PERL_LIBRARY} debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt)
|
||||
TARGET_LINK_LIBRARIES(world ${SERVER_LIBS})
|
||||
|
||||
IF(WIN32)
|
||||
TARGET_LINK_LIBRARIES(world "ws2_32" "psapi" "iphlpapi" "userenv")
|
||||
ENDIF(WIN32)
|
||||
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(world "${CMAKE_DL_LIBS}")
|
||||
TARGET_LINK_LIBRARIES(world "z")
|
||||
TARGET_LINK_LIBRARIES(world "m")
|
||||
IF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(world "rt")
|
||||
ENDIF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(world "pthread")
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ENDIF(UNIX)
|
||||
IF(EQEMU_BUILD_PERL)
|
||||
TARGET_LINK_LIBRARIES(world ${PERL_LIBRARY})
|
||||
ENDIF(EQEMU_BUILD_PERL)
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
@ -231,11 +231,7 @@ INSTALL(TARGETS zone RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
ADD_DEFINITIONS(-DZONE)
|
||||
|
||||
TARGET_LINK_LIBRARIES(zone common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt)
|
||||
|
||||
IF(WIN32)
|
||||
TARGET_LINK_LIBRARIES(zone "ws2_32" "psapi" "iphlpapi" "userenv")
|
||||
ENDIF(WIN32)
|
||||
TARGET_LINK_LIBRARIES(zone ${SERVER_LIBS})
|
||||
|
||||
IF(EQEMU_BUILD_PERL)
|
||||
TARGET_LINK_LIBRARIES(zone ${PERL_LIBRARY})
|
||||
@ -245,15 +241,4 @@ IF(EQEMU_BUILD_LUA)
|
||||
TARGET_LINK_LIBRARIES(zone luabind ${LUA_LIBRARY})
|
||||
ENDIF(EQEMU_BUILD_LUA)
|
||||
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(zone "${CMAKE_DL_LIBS}")
|
||||
TARGET_LINK_LIBRARIES(zone "z")
|
||||
TARGET_LINK_LIBRARIES(zone "m")
|
||||
IF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(zone "rt")
|
||||
ENDIF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(zone "pthread")
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ENDIF(UNIX)
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
@ -66,7 +66,6 @@
|
||||
#include "../common/event/event_loop.h"
|
||||
#include "../common/event/timer.h"
|
||||
#include "../common/net/eqstream.h"
|
||||
#include "../common/net/relay_link.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user