Moved client data passing to a dedicated ClientSession class instead of passing through a bunch of pointers at init

This commit is contained in:
2026-02-08 19:20:27 +01:00
parent e61a429f24
commit 757d0d251d
7 changed files with 192 additions and 56 deletions

View File

@@ -0,0 +1,71 @@
// client_session.cpp - Client Session data for ColumnLynx
// Copyright (C) 2026 DcruBro
// Distributed under the terms of the GNU General Public License, either version 2 only or version 3. See LICENSES/ for details.
#include <columnlynx/client/client_session.hpp>
namespace ColumnLynx {
std::shared_ptr<ClientState> ClientSession::getClientState() const {
std::shared_lock lock(mMutex);
return mClientState;
}
void ClientSession::setClientState(std::shared_ptr<ClientState> state) {
std::unique_lock lock(mMutex);
mClientState = state;
}
const std::shared_ptr<Utils::LibSodiumWrapper>& ClientSession::getSodiumWrapper() const {
return getClientState()->sodiumWrapper;
}
const SymmetricKey& ClientSession::getAESKey() const {
return getClientState()->aesKey;
}
bool ClientSession::isInsecureMode() const {
return getClientState()->insecureMode;
}
const std::string& ClientSession::getConfigPath() const {
return getClientState()->configPath;
}
const std::shared_ptr<Net::VirtualInterface>& ClientSession::getVirtualInterface() const {
return getClientState()->virtualInterface;
}
uint64_t ClientSession::getSessionID() const {
return getClientState()->sessionID;
}
void ClientSession::setSodiumWrapper(std::shared_ptr<Utils::LibSodiumWrapper> sodiumWrapper) {
std::unique_lock lock(mMutex);
mClientState->sodiumWrapper = sodiumWrapper;
}
void ClientSession::setAESKey(const SymmetricKey& aesKey) {
std::unique_lock lock(mMutex);
mClientState->aesKey = aesKey;
}
void ClientSession::setInsecureMode(bool insecureMode) {
std::unique_lock lock(mMutex);
mClientState->insecureMode = insecureMode;
}
void ClientSession::setConfigPath(const std::string& configPath) {
std::unique_lock lock(mMutex);
mClientState->configPath = configPath;
}
void ClientSession::setVirtualInterface(std::shared_ptr<Net::VirtualInterface> virtualInterface) {
std::unique_lock lock(mMutex);
mClientState->virtualInterface = virtualInterface;
}
void ClientSession::setSessionID(uint64_t sessionID) {
std::unique_lock lock(mMutex);
mClientState->sessionID = sessionID;
}
}

View File

@@ -11,6 +11,8 @@
#include <columnlynx/client/net/udp/udp_client.hpp>
#include <cxxopts.hpp>
#include <columnlynx/common/net/virtual_interface.hpp>
#include <columnlynx/client/client_session.hpp>
#include <thread>
#if defined(__WIN32__)
#include <windows.h>
@@ -99,24 +101,34 @@ int main(int argc, char** argv) {
#endif
}
struct ClientState initialState{};
initialState.configPath = configPath;
initialState.insecureMode = insecureMode;
std::shared_ptr<VirtualInterface> tun = std::make_shared<VirtualInterface>(optionsObj["interface"].as<std::string>());
log("Using virtual interface: " + tun->getName());
initialState.virtualInterface = tun;
std::shared_ptr<LibSodiumWrapper> sodiumWrapper = std::make_shared<LibSodiumWrapper>();
debug("Public Key: " + Utils::bytesToHexString(sodiumWrapper->getPublicKey(), 32));
debug("Private Key: " + Utils::bytesToHexString(sodiumWrapper->getPrivateKey(), 64));
initialState.sodiumWrapper = sodiumWrapper;
std::shared_ptr<std::array<uint8_t, 32>> aesKey = std::make_shared<std::array<uint8_t, 32>>();
aesKey->fill(0); // Defualt zeroed state until modified by handshake
std::shared_ptr<uint64_t> sessionID = std::make_shared<uint64_t>(0);
std::array<uint8_t, 32> aesKey = std::array<uint8_t, 32>();
aesKey.fill(0); // Defualt zeroed state until modified by handshake
uint64_t sessionID = 0;
initialState.aesKey = aesKey;
initialState.sessionID = sessionID;
ColumnLynx::ClientSession::getInstance().setClientState(std::make_shared<ClientState>(std::move(initialState))); // Set initial state
if (insecureMode) {
warn("You have started the client with the --ignore-whitelist. This means that the client will NOT attempt to verify the server's public key. This is INSECURE and SHOULDN'T be used!");
}
asio::io_context io;
auto client = std::make_shared<ColumnLynx::Net::TCP::TCPClient>(io, host, port, sodiumWrapper, aesKey, sessionID, insecureMode, configPath, tun);
auto udpClient = std::make_shared<ColumnLynx::Net::UDP::UDPClient>(io, host, port, aesKey, sessionID, tun);
auto client = std::make_shared<ColumnLynx::Net::TCP::TCPClient>(io, host, port); // TODO: Move to ClientSession state
auto udpClient = std::make_shared<ColumnLynx::Net::UDP::UDPClient>(io, host, port);
client->start();
udpClient->start();

View File

@@ -50,6 +50,8 @@ namespace ColumnLynx::Net::TCP {
mLibSodiumWrapper->getXPublicKey(),
mLibSodiumWrapper->getXPublicKey() + crypto_box_PUBLICKEYBYTES
);*/
const auto& mLibSodiumWrapper = ClientSession::getInstance().getSodiumWrapper();
payload.insert(payload.end(),
mLibSodiumWrapper->getPublicKey(),
mLibSodiumWrapper->getPublicKey() + crypto_sign_PUBLICKEYBYTES
@@ -130,11 +132,9 @@ namespace ColumnLynx::Net::TCP {
mHandler->socket().shutdown(tcp::socket::shutdown_both, ec);
mHandler->socket().close(ec);
mConnected = false;
mGlobalKeyRef = nullptr;
if (mSessionIDRef) {
*mSessionIDRef = 0;
}
ClientSession::getInstance().setAESKey({}); // Clear AES key with all zeros
ClientSession::getInstance().setSessionID(0);
return;
}
@@ -155,9 +155,10 @@ namespace ColumnLynx::Net::TCP {
Utils::log("Received server identity. Public Key: " + hexServerPub);
// Verify pubkey against whitelisted_keys
std::vector<std::string> whitelistedKeys = Utils::getWhitelistedKeys(mConfigDirPath);
const std::string& configPath = ClientSession::getInstance().getConfigPath();
std::vector<std::string> whitelistedKeys = Utils::getWhitelistedKeys(configPath);
if (std::find(whitelistedKeys.begin(), whitelistedKeys.end(), Utils::bytesToHexString(mServerPublicKey, 32)) == whitelistedKeys.end()) { // Key verification is handled in later steps of the handshake
if (!mInsecureMode) {
if (!ClientSession::getInstance().isInsecureMode()) {
Utils::error("Server public key not in whitelisted_keys. Terminating connection.");
disconnect();
return;
@@ -193,16 +194,14 @@ namespace ColumnLynx::Net::TCP {
// Generate AES key and send confirmation
mConnectionAESKey = Utils::LibSodiumWrapper::generateRandom256Bit();
if (mGlobalKeyRef) { // Copy to the global reference
std::copy(mConnectionAESKey.begin(), mConnectionAESKey.end(), mGlobalKeyRef->begin());
}
ClientSession::getInstance().setAESKey(mConnectionAESKey);
AsymNonce nonce{};
randombytes_buf(nonce.data(), nonce.size());
// TODO: This is pretty redundant, it should return the required type directly
std::array<uint8_t, 32> arrayPrivateKey;
std::copy(mLibSodiumWrapper->getXPrivateKey(),
mLibSodiumWrapper->getXPrivateKey() + 32,
std::copy(ClientSession::getInstance().getSodiumWrapper()->getXPrivateKey(),
ClientSession::getInstance().getSodiumWrapper()->getXPrivateKey() + 32,
arrayPrivateKey.begin());
std::vector<uint8_t> encr = Utils::LibSodiumWrapper::encryptAsymmetric(
@@ -249,15 +248,14 @@ namespace ColumnLynx::Net::TCP {
Utils::log("Connection established with Session ID: " + std::to_string(mConnectionSessionID));
if (mSessionIDRef) { // Copy to the global reference
*mSessionIDRef = mConnectionSessionID;
}
ClientSession::getInstance().setSessionID(mConnectionSessionID);
uint32_t clientIP = ntohl(mTunConfig.clientIP);
uint32_t serverIP = ntohl(mTunConfig.serverIP);
uint8_t prefixLen = mTunConfig.prefixLength;
uint16_t mtu = mTunConfig.mtu;
const auto& mTun = ClientSession::getInstance().getVirtualInterface();
if (mTun) {
mTun->configureIP(clientIP, serverIP, prefixLen, mtu);
}

View File

@@ -48,7 +48,7 @@ namespace ColumnLynx::Net::UDP {
UDPPacketHeader hdr{};
randombytes_buf(hdr.nonce.data(), hdr.nonce.size());
if (mAesKeyRef == nullptr || mSessionIDRef == nullptr) {
if (ClientSession::getInstance().getAESKey().empty() || ClientSession::getInstance().getSessionID() == 0) {
Utils::error("UDP Client AES key or Session ID reference is null!");
return;
}
@@ -57,7 +57,7 @@ namespace ColumnLynx::Net::UDP {
auto encryptedPayload = Utils::LibSodiumWrapper::encryptMessage(
reinterpret_cast<const uint8_t*>(data.data()), data.size(),
*mAesKeyRef, hdr.nonce, "udp-data"
ClientSession::getInstance().getAESKey(), hdr.nonce, "udp-data"
//std::string(reinterpret_cast<const char*>(&mSessionIDRef), sizeof(uint64_t))
);
@@ -67,9 +67,10 @@ namespace ColumnLynx::Net::UDP {
reinterpret_cast<uint8_t*>(&hdr),
reinterpret_cast<uint8_t*>(&hdr) + sizeof(UDPPacketHeader)
);
uint64_t sessionID = ClientSession::getInstance().getSessionID();
packet.insert(packet.end(),
reinterpret_cast<uint8_t*>(mSessionIDRef.get()),
reinterpret_cast<uint8_t*>(mSessionIDRef.get()) + sizeof(uint64_t)
reinterpret_cast<uint8_t*>(&sessionID),
reinterpret_cast<uint8_t*>(&sessionID) + sizeof(uint64_t)
);
packet.insert(packet.end(), encryptedPayload.begin(), encryptedPayload.end());
@@ -120,8 +121,8 @@ namespace ColumnLynx::Net::UDP {
uint64_t sessionID;
std::memcpy(&sessionID, mRecvBuffer.data() + sizeof(UDPPacketHeader), sizeof(uint64_t));
if (sessionID != *mSessionIDRef) {
Utils::warn("Got packet that isn't for me! Dropping!");
if (sessionID != ClientSession::getInstance().getSessionID()) {
Utils::warn("This packet that isn't for me! Dropping!");
return;
}
@@ -131,13 +132,13 @@ namespace ColumnLynx::Net::UDP {
mRecvBuffer.begin() + bytes
);
if (mAesKeyRef == nullptr) {
if (ClientSession::getInstance().getAESKey().empty()) {
Utils::error("UDP Client AES key reference is null!");
return;
}
std::vector<uint8_t> plaintext = Utils::LibSodiumWrapper::decryptMessage(
ciphertext.data(), ciphertext.size(), *mAesKeyRef, hdr.nonce, "udp-data"
ciphertext.data(), ciphertext.size(), ClientSession::getInstance().getAESKey(), hdr.nonce, "udp-data"
//std::string(reinterpret_cast<const char*>(&mSessionIDRef), sizeof(uint64_t))
);
@@ -149,6 +150,7 @@ namespace ColumnLynx::Net::UDP {
Utils::debug("UDP Client received packet from " + mRemoteEndpoint.address().to_string() + " - Packet size: " + std::to_string(bytes));
// Write to TUN
const auto& mTunRef = ClientSession::getInstance().getVirtualInterface();
if (mTunRef) {
mTunRef->writePacket(plaintext);
}