TESTING: protocol version 2

This commit is contained in:
2026-02-10 13:27:15 +01:00
parent 316498c745
commit 14298453b3
15 changed files with 110 additions and 74 deletions

View File

@@ -35,7 +35,7 @@ namespace ColumnLynx {
return getClientState()->virtualInterface;
}
uint64_t ClientSession::getSessionID() const {
uint32_t ClientSession::getSessionID() const {
return getClientState()->sessionID;
}
@@ -64,7 +64,7 @@ namespace ColumnLynx {
mClientState->virtualInterface = virtualInterface;
}
void ClientSession::setSessionID(uint64_t sessionID) {
void ClientSession::setSessionID(uint32_t sessionID) {
std::unique_lock lock(mMutex);
mClientState->sessionID = sessionID;
}

View File

@@ -104,6 +104,9 @@ int main(int argc, char** argv) {
struct ClientState initialState{};
initialState.configPath = configPath;
initialState.insecureMode = insecureMode;
initialState.send_cnt = 0;
initialState.recv_cnt = 0;
randombytes_buf(&initialState.noncePrefix, sizeof(uint32_t)); // Randomize nonce prefix
std::shared_ptr<VirtualInterface> tun = std::make_shared<VirtualInterface>(optionsObj["interface"].as<std::string>());
log("Using virtual interface: " + tun->getName());
@@ -116,7 +119,7 @@ int main(int argc, char** argv) {
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;
uint32_t sessionID = 0;
initialState.aesKey = aesKey;
initialState.sessionID = sessionID;

View File

@@ -244,7 +244,7 @@ namespace ColumnLynx::Net::TCP {
std::memcpy(&mConnectionSessionID, decrypted.data(), sizeof(mConnectionSessionID));
std::memcpy(&mTunConfig, decrypted.data() + sizeof(mConnectionSessionID), sizeof(Protocol::TunConfig));
mConnectionSessionID = Utils::cbe64toh(mConnectionSessionID);
mConnectionSessionID = ntohl(mConnectionSessionID);
Utils::log("Connection established with Session ID: " + std::to_string(mConnectionSessionID));

View File

@@ -46,7 +46,12 @@ namespace ColumnLynx::Net::UDP {
void UDPClient::sendMessage(const std::string& data) {
UDPPacketHeader hdr{};
randombytes_buf(hdr.nonce.data(), hdr.nonce.size());
uint8_t nonce[12];
uint32_t prefix = ClientSession::getInstance().getNoncePrefix();
uint64_t sendCount = ClientSession::getInstance().getSendCount();
memcpy(nonce, &prefix, sizeof(uint32_t)); // Prefix nonce with client-specific random value
memcpy(nonce + sizeof(uint32_t), &sendCount, sizeof(uint64_t)); // Use send count as nonce suffix to ensure uniqueness
std::copy_n(nonce, 12, hdr.nonce.data());
if (ClientSession::getInstance().getAESKey().empty() || ClientSession::getInstance().getSessionID() == 0) {
Utils::error("UDP Client AES key or Session ID reference is null!");
@@ -62,7 +67,7 @@ namespace ColumnLynx::Net::UDP {
);
std::vector<uint8_t> packet;
packet.reserve(sizeof(UDPPacketHeader) + sizeof(uint64_t) + encryptedPayload.size());
packet.reserve(sizeof(UDPPacketHeader) + encryptedPayload.size());
packet.insert(packet.end(),
reinterpret_cast<uint8_t*>(&hdr),
reinterpret_cast<uint8_t*>(&hdr) + sizeof(UDPPacketHeader)
@@ -76,6 +81,8 @@ namespace ColumnLynx::Net::UDP {
mSocket.send_to(asio::buffer(packet), mRemoteEndpoint);
Utils::debug("Sent UDP packet of size " + std::to_string(packet.size()));
ClientSession::getInstance().incrementSendCount();
}
void UDPClient::stop() {

View File

@@ -5,13 +5,13 @@
#include <columnlynx/common/net/session_registry.hpp>
namespace ColumnLynx::Net {
void SessionRegistry::put(uint64_t sessionID, std::shared_ptr<SessionState> state) {
void SessionRegistry::put(uint32_t sessionID, std::shared_ptr<SessionState> state) {
std::unique_lock lock(mMutex);
mSessions[sessionID] = std::move(state);
mIPSessions[mSessions[sessionID]->clientTunIP] = mSessions[sessionID];
}
std::shared_ptr<const SessionState> SessionRegistry::get(uint64_t sessionID) const {
std::shared_ptr<const SessionState> SessionRegistry::get(uint32_t sessionID) const {
std::shared_lock lock(mMutex);
auto it = mSessions.find(sessionID);
return (it == mSessions.end()) ? nullptr : it->second;
@@ -23,14 +23,14 @@ namespace ColumnLynx::Net {
return (it == mIPSessions.end()) ? nullptr : it->second;
}
std::unordered_map<uint64_t, std::shared_ptr<SessionState>> SessionRegistry::snapshot() const {
std::unordered_map<uint64_t, std::shared_ptr<SessionState>> snap;
std::unordered_map<uint32_t, std::shared_ptr<SessionState>> SessionRegistry::snapshot() const {
std::unordered_map<uint32_t, std::shared_ptr<SessionState>> snap;
std::shared_lock lock(mMutex);
snap = mSessions;
return snap;
}
void SessionRegistry::erase(uint64_t sessionID) {
void SessionRegistry::erase(uint32_t sessionID) {
std::unique_lock lock(mMutex);
mSessions.erase(sessionID);
}
@@ -77,7 +77,7 @@ namespace ColumnLynx::Net {
return 0;
}
void SessionRegistry::lockIP(uint64_t sessionID, uint32_t ip) {
void SessionRegistry::lockIP(uint32_t sessionID, uint32_t ip) {
std::unique_lock lock(mMutex);
mSessionIPs[sessionID] = ip;
@@ -87,7 +87,7 @@ namespace ColumnLynx::Net {
mIPSessions[ip] = mSessions.find(sessionID)->second;
}
void SessionRegistry::deallocIP(uint64_t sessionID) {
void SessionRegistry::deallocIP(uint32_t sessionID) {
std::unique_lock lock(mMutex);
auto it = mSessionIPs.find(sessionID);

View File

@@ -93,7 +93,7 @@ namespace ColumnLynx::Utils {
}
unsigned char protocolVersion() {
return 1;
return 2;
}
std::string bytesToHexString(const uint8_t* bytes, size_t length) {

View File

@@ -66,7 +66,7 @@ namespace ColumnLynx::Net::TCP {
Utils::log("Initiated graceful disconnect (half-close) to " + mRemoteIP);
}
uint64_t TCPConnection::getSessionID() const {
uint32_t TCPConnection::getSessionID() const {
return mConnectionSessionID;
}
@@ -247,11 +247,11 @@ namespace ColumnLynx::Net::TCP {
tunConfig.dns1 = htonl(0x08080808); // 8.8.8.8
tunConfig.dns2 = 0;
uint64_t sessionIDNet = Utils::chtobe64(mConnectionSessionID);
uint32_t sessionIDNet = htonl(mConnectionSessionID);
std::vector<uint8_t> payload(sizeof(uint64_t) + sizeof(tunConfig));
std::memcpy(payload.data(), &sessionIDNet, sizeof(uint64_t));
std::memcpy(payload.data() + sizeof(uint64_t), &tunConfig, sizeof(tunConfig));
std::vector<uint8_t> payload(sizeof(uint32_t) + sizeof(tunConfig));
std::memcpy(payload.data(), &sessionIDNet, sizeof(uint32_t));
std::memcpy(payload.data() + sizeof(uint32_t), &tunConfig, sizeof(tunConfig));
std::vector<uint8_t> encryptedPayload = Utils::LibSodiumWrapper::encryptMessage(
payload.data(), payload.size(),
@@ -263,6 +263,7 @@ namespace ColumnLynx::Net::TCP {
// Add to session registry
Utils::log("Handshake with " + reqAddr + " completed successfully. Session ID assigned (" + std::to_string(mConnectionSessionID) + ").");
auto session = std::make_shared<SessionState>(mConnectionAESKey, std::chrono::hours(12), clientIP, htonl(0x0A0A0001), mConnectionSessionID);
session->setBaseNonce(); // Set it
SessionRegistry::getInstance().put(mConnectionSessionID, std::move(session));
SessionRegistry::getInstance().lockIP(mConnectionSessionID, clientIP);

View File

@@ -26,16 +26,17 @@ namespace ColumnLynx::Net::UDP {
}
void UDPServer::mHandlePacket(std::size_t bytes) {
if (bytes < sizeof(UDPPacketHeader))
if (bytes < sizeof(UDPPacketHeader) + sizeof(uint32_t))
return;
const auto* hdr = reinterpret_cast<UDPPacketHeader*>(mRecvBuffer.data());
// Get plaintext session ID (assuming first 8 bytes after nonce (header))
uint64_t sessionID = 0;
std::memcpy(&sessionID, mRecvBuffer.data() + sizeof(UDPPacketHeader), sizeof(uint64_t));
// Get plaintext session ID (assuming first 4 bytes after nonce (header))
uint32_t sessionIDNet = 0;
std::memcpy(&sessionIDNet, mRecvBuffer.data() + sizeof(UDPPacketHeader), sizeof(uint32_t));
uint32_t sessionID = ntohl(sessionIDNet);
auto it = mRecvBuffer.begin() + sizeof(UDPPacketHeader) + sizeof(uint64_t);
auto it = mRecvBuffer.begin() + sizeof(UDPPacketHeader) + sizeof(uint32_t);
std::vector<uint8_t> encryptedPayload(it, mRecvBuffer.begin() + bytes);
// Get associated session state
@@ -54,7 +55,7 @@ namespace ColumnLynx::Net::UDP {
encryptedPayload.data(), encryptedPayload.size(),
session->aesKey,
hdr->nonce, "udp-data"
//std::string(reinterpret_cast<const char*>(&sessionID), sizeof(uint64_t))
//std::string(reinterpret_cast<const char*>(&sessionID), sizeof(uint32_t))
);
Utils::debug("Passed decryption");
@@ -76,7 +77,7 @@ namespace ColumnLynx::Net::UDP {
}
}
void UDPServer::sendData(const uint64_t sessionID, const std::string& data) {
void UDPServer::sendData(uint32_t sessionID, const std::string& data) {
// Find the IPv4/IPv6 endpoint for the session
std::shared_ptr<const SessionState> session = SessionRegistry::getInstance().get(sessionID);
if (!session) {
@@ -92,23 +93,29 @@ namespace ColumnLynx::Net::UDP {
// Prepare packet
UDPPacketHeader hdr{};
randombytes_buf(hdr.nonce.data(), hdr.nonce.size());
uint8_t nonce[12];
uint32_t prefix = session->noncePrefix;
uint64_t sendCount = const_cast<SessionState*>(session.get())->send_ctr.fetch_add(1, std::memory_order_relaxed);
memcpy(nonce, &prefix, sizeof(uint32_t)); // Prefix nonce
memcpy(nonce + sizeof(uint32_t), &sendCount, sizeof(uint64_t)); // Use send count as nonce suffix to ensure uniqueness
std::copy_n(nonce, 12, hdr.nonce.data());
auto encryptedPayload = Utils::LibSodiumWrapper::encryptMessage(
reinterpret_cast<const uint8_t*>(data.data()), data.size(),
session->aesKey, hdr.nonce, "udp-data"
//std::string(reinterpret_cast<const char*>(&sessionID), sizeof(uint64_t))
//std::string(reinterpret_cast<const char*>(&sessionID), sizeof(uint32_t))
);
std::vector<uint8_t> packet;
packet.reserve(sizeof(UDPPacketHeader) + sizeof(uint64_t) + encryptedPayload.size());
packet.reserve(sizeof(UDPPacketHeader) + sizeof(uint32_t) + encryptedPayload.size());
packet.insert(packet.end(),
reinterpret_cast<uint8_t*>(&hdr),
reinterpret_cast<uint8_t*>(&hdr) + sizeof(UDPPacketHeader)
);
uint32_t sessionIDNet = htonl(sessionID);
packet.insert(packet.end(),
reinterpret_cast<const uint8_t*>(&sessionID),
reinterpret_cast<const uint8_t*>(&sessionID) + sizeof(sessionID)
reinterpret_cast<const uint8_t*>(&sessionIDNet),
reinterpret_cast<const uint8_t*>(&sessionIDNet) + sizeof(sessionIDNet)
);
packet.insert(packet.end(), encryptedPayload.begin(), encryptedPayload.end());