Comment some code
This commit is contained in:
@@ -63,17 +63,26 @@ namespace ColumnLynx::Net::TCP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Starts the TCP Client and initiaties the handshake
|
||||||
void start();
|
void start();
|
||||||
|
// Sends a TCP message to the server
|
||||||
void sendMessage(ClientMessageType type, const std::string& data = "");
|
void sendMessage(ClientMessageType type, const std::string& data = "");
|
||||||
|
// Attempt to gracefully disconnect from the server
|
||||||
void disconnect(bool echo = true);
|
void disconnect(bool echo = true);
|
||||||
|
|
||||||
|
// Get the handshake status
|
||||||
bool isHandshakeComplete() const;
|
bool isHandshakeComplete() const;
|
||||||
|
// Get the connection status
|
||||||
bool isConnected() const;
|
bool isConnected() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Start the heartbeat routine
|
||||||
void mStartHeartbeat();
|
void mStartHeartbeat();
|
||||||
|
// Handle an incoming TCP message
|
||||||
void mHandleMessage(ServerMessageType type, const std::string& data);
|
void mHandleMessage(ServerMessageType type, const std::string& data);
|
||||||
|
|
||||||
|
// TODO: Move ptrs to smart ptrs
|
||||||
|
|
||||||
bool mConnected = false;
|
bool mConnected = false;
|
||||||
bool mHandshakeComplete = false;
|
bool mHandshakeComplete = false;
|
||||||
tcp::resolver mResolver;
|
tcp::resolver mResolver;
|
||||||
|
|||||||
@@ -25,12 +25,17 @@ namespace ColumnLynx::Net::UDP {
|
|||||||
mStartReceive();
|
mStartReceive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start the UDP client
|
||||||
void start();
|
void start();
|
||||||
|
// Send a UDP message
|
||||||
void sendMessage(const std::string& data = "");
|
void sendMessage(const std::string& data = "");
|
||||||
|
// Stop the UDP client
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Start the UDP listener routine
|
||||||
void mStartReceive();
|
void mStartReceive();
|
||||||
|
// Handle an incoming UDP message
|
||||||
void mHandlePacket(std::size_t bytes);
|
void mHandlePacket(std::size_t bytes);
|
||||||
|
|
||||||
asio::ip::udp::socket mSocket;
|
asio::ip::udp::socket mSocket;
|
||||||
|
|||||||
@@ -35,12 +35,14 @@ namespace ColumnLynx::Utils {
|
|||||||
public:
|
public:
|
||||||
LibSodiumWrapper();
|
LibSodiumWrapper();
|
||||||
|
|
||||||
|
// These are pretty self-explanatory
|
||||||
|
|
||||||
uint8_t* getPublicKey();
|
uint8_t* getPublicKey();
|
||||||
uint8_t* getPrivateKey();
|
uint8_t* getPrivateKey();
|
||||||
uint8_t* getXPublicKey() { return mXPublicKey.data(); }
|
uint8_t* getXPublicKey() { return mXPublicKey.data(); }
|
||||||
uint8_t* getXPrivateKey() { return mXPrivateKey.data(); }
|
uint8_t* getXPrivateKey() { return mXPrivateKey.data(); }
|
||||||
|
|
||||||
// Dangerous!
|
// Set the Asymmetric signing keypair. This also regenerates the corresponding encryption keypair; Dangerous!
|
||||||
void setKeys(PublicKey pk, PrivateKey sk) {
|
void setKeys(PublicKey pk, PrivateKey sk) {
|
||||||
mPublicKey = pk;
|
mPublicKey = pk;
|
||||||
mPrivateKey = sk;
|
mPrivateKey = sk;
|
||||||
@@ -54,18 +56,14 @@ namespace ColumnLynx::Utils {
|
|||||||
|
|
||||||
// Generates a random 256-bit (32-byte) array
|
// Generates a random 256-bit (32-byte) array
|
||||||
static std::array<uint8_t, 32> generateRandom256Bit();
|
static std::array<uint8_t, 32> generateRandom256Bit();
|
||||||
|
|
||||||
|
// Sign a message with the stored private key
|
||||||
static inline Signature signMessage(const uint8_t* msg, size_t len, const PrivateKey& sk) {
|
static inline Signature signMessage(const uint8_t* msg, size_t len, const PrivateKey& sk) {
|
||||||
Signature sig{};
|
Signature sig{};
|
||||||
crypto_sign_detached(sig.data(), nullptr, msg, len, sk.data());
|
crypto_sign_detached(sig.data(), nullptr, msg, len, sk.data());
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool verifyMessage(const uint8_t* msg, size_t len,
|
|
||||||
const Signature& sig, const PublicKey& pk) {
|
|
||||||
return crypto_sign_verify_detached(sig.data(), msg, len, pk.data()) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overloads for std::string / std::array
|
// Overloads for std::string / std::array
|
||||||
static inline Signature signMessage(const std::string& msg, const PrivateKey& sk) {
|
static inline Signature signMessage(const std::string& msg, const PrivateKey& sk) {
|
||||||
return signMessage(reinterpret_cast<const uint8_t*>(msg.data()), msg.size(), sk);
|
return signMessage(reinterpret_cast<const uint8_t*>(msg.data()), msg.size(), sk);
|
||||||
@@ -82,6 +80,11 @@ namespace ColumnLynx::Utils {
|
|||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify a message with a given public key
|
||||||
|
static inline bool verifyMessage(const uint8_t* msg, size_t len, const Signature& sig, const PublicKey& pk) {
|
||||||
|
return crypto_sign_verify_detached(sig.data(), msg, len, pk.data()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool verifyMessage(const std::string& msg, const Signature& sig, const PublicKey& pk) {
|
static inline bool verifyMessage(const std::string& msg, const Signature& sig, const PublicKey& pk) {
|
||||||
return verifyMessage(reinterpret_cast<const uint8_t*>(msg.data()), msg.size(), sig, pk);
|
return verifyMessage(reinterpret_cast<const uint8_t*>(msg.data()), msg.size(), sig, pk);
|
||||||
}
|
}
|
||||||
@@ -96,7 +99,7 @@ namespace ColumnLynx::Utils {
|
|||||||
return crypto_sign_verify_detached(sig.data(), msg, len, pk_raw) == 0;
|
return crypto_sign_verify_detached(sig.data(), msg, len, pk_raw) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt with ChaCha20-Poly1305 (returns ciphertext as bytes)
|
// Encrypt symmetrically with ChaCha20-Poly1305; returns ciphertext as bytes
|
||||||
static inline std::vector<uint8_t> encryptMessage(
|
static inline std::vector<uint8_t> encryptMessage(
|
||||||
const uint8_t* plaintext, size_t len,
|
const uint8_t* plaintext, size_t len,
|
||||||
const SymmetricKey& key, const Nonce& nonce,
|
const SymmetricKey& key, const Nonce& nonce,
|
||||||
@@ -119,7 +122,7 @@ namespace ColumnLynx::Utils {
|
|||||||
return ciphertext;
|
return ciphertext;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt with ChaCha20-Poly1305 (returns plaintext as bytes)
|
// Decrypt symmetrically with ChaCha20-Poly1305; Returns plaintext as bytes
|
||||||
static inline std::vector<uint8_t> decryptMessage(
|
static inline std::vector<uint8_t> decryptMessage(
|
||||||
const uint8_t* ciphertext, size_t len,
|
const uint8_t* ciphertext, size_t len,
|
||||||
const SymmetricKey& key, const Nonce& nonce,
|
const SymmetricKey& key, const Nonce& nonce,
|
||||||
@@ -145,12 +148,14 @@ namespace ColumnLynx::Utils {
|
|||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a random nonce
|
||||||
static inline Nonce generateNonce() {
|
static inline Nonce generateNonce() {
|
||||||
Nonce n{};
|
Nonce n{};
|
||||||
randombytes_buf(n.data(), n.size());
|
randombytes_buf(n.data(), n.size());
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encrypt message asymmetrically; Returns ciphertext as bytes
|
||||||
static inline std::vector<uint8_t> encryptAsymmetric(
|
static inline std::vector<uint8_t> encryptAsymmetric(
|
||||||
const uint8_t* plaintext, size_t len,
|
const uint8_t* plaintext, size_t len,
|
||||||
const AsymNonce& nonce,
|
const AsymNonce& nonce,
|
||||||
@@ -171,6 +176,7 @@ namespace ColumnLynx::Utils {
|
|||||||
return ciphertext;
|
return ciphertext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decrypt message asymmetrically; Returns plaintext as bytes
|
||||||
static inline std::vector<uint8_t> decryptAsymmetric(
|
static inline std::vector<uint8_t> decryptAsymmetric(
|
||||||
const uint8_t* ciphertext, size_t len,
|
const uint8_t* ciphertext, size_t len,
|
||||||
const AsymNonce& nonce,
|
const AsymNonce& nonce,
|
||||||
@@ -194,97 +200,99 @@ namespace ColumnLynx::Utils {
|
|||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool verifyCertificateWithSystemCAs(const std::vector<uint8_t>& cert_der) {
|
// Verify a public key (certificate) against system-installed CAs
|
||||||
// Parse DER-encoded certificate
|
static inline bool verifyCertificateWithSystemCAs(const std::vector<uint8_t>& cert_der) {
|
||||||
const unsigned char* p = cert_der.data();
|
// Parse DER-encoded certificate
|
||||||
std::unique_ptr<X509, decltype(&X509_free)> cert(
|
const unsigned char* p = cert_der.data();
|
||||||
d2i_X509(nullptr, &p, cert_der.size()), X509_free
|
std::unique_ptr<X509, decltype(&X509_free)> cert(
|
||||||
);
|
d2i_X509(nullptr, &p, cert_der.size()), X509_free
|
||||||
if (!cert) {
|
);
|
||||||
return false;
|
if (!cert) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a certificate store
|
||||||
|
std::unique_ptr<X509_STORE, decltype(&X509_STORE_free)> store(
|
||||||
|
X509_STORE_new(), X509_STORE_free
|
||||||
|
);
|
||||||
|
if (!store) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load system default CA paths (/etc/ssl/certs, etc.)
|
||||||
|
if (X509_STORE_set_default_paths(store.get()) != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a verification context
|
||||||
|
std::unique_ptr<X509_STORE_CTX, decltype(&X509_STORE_CTX_free)> ctx(
|
||||||
|
X509_STORE_CTX_new(), X509_STORE_CTX_free
|
||||||
|
);
|
||||||
|
if (!ctx) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize verification context
|
||||||
|
if (X509_STORE_CTX_init(ctx.get(), store.get(), cert.get(), nullptr) != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the actual certificate verification
|
||||||
|
int result = X509_verify_cert(ctx.get());
|
||||||
|
return result == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a certificate store
|
|
||||||
std::unique_ptr<X509_STORE, decltype(&X509_STORE_free)> store(
|
|
||||||
X509_STORE_new(), X509_STORE_free
|
|
||||||
);
|
|
||||||
if (!store) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load system default CA paths (/etc/ssl/certs, etc.)
|
|
||||||
if (X509_STORE_set_default_paths(store.get()) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a verification context
|
|
||||||
std::unique_ptr<X509_STORE_CTX, decltype(&X509_STORE_CTX_free)> ctx(
|
|
||||||
X509_STORE_CTX_new(), X509_STORE_CTX_free
|
|
||||||
);
|
|
||||||
if (!ctx) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize verification context
|
|
||||||
if (X509_STORE_CTX_init(ctx.get(), store.get(), cert.get(), nullptr) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform the actual certificate verification
|
|
||||||
int result = X509_verify_cert(ctx.get());
|
|
||||||
return result == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::vector<std::string> getCertificateHostname(const std::vector<uint8_t>& cert_der) {
|
// Extract the hostnames (Subject Alternative Names and Common Names) out of a public key (certificate)
|
||||||
std::vector<std::string> names;
|
static inline std::vector<std::string> getCertificateHostname(const std::vector<uint8_t>& cert_der) {
|
||||||
|
std::vector<std::string> names;
|
||||||
|
|
||||||
if (cert_der.empty())
|
if (cert_der.empty())
|
||||||
return names;
|
return names;
|
||||||
|
|
||||||
// Parse DER certificate
|
// Parse DER certificate
|
||||||
const unsigned char* p = cert_der.data();
|
const unsigned char* p = cert_der.data();
|
||||||
X509* cert = d2i_X509(nullptr, &p, cert_der.size());
|
X509* cert = d2i_X509(nullptr, &p, cert_der.size());
|
||||||
if (!cert)
|
if (!cert)
|
||||||
return names;
|
return names;
|
||||||
|
|
||||||
// --- Subject Alternative Names (SAN) ---
|
// --- Subject Alternative Names (SAN) ---
|
||||||
GENERAL_NAMES* san_names =
|
GENERAL_NAMES* san_names =
|
||||||
(GENERAL_NAMES*)X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr);
|
(GENERAL_NAMES*)X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr);
|
||||||
|
|
||||||
if (san_names) {
|
if (san_names) {
|
||||||
int san_count = sk_GENERAL_NAME_num(san_names);
|
int san_count = sk_GENERAL_NAME_num(san_names);
|
||||||
for (int i = 0; i < san_count; i++) {
|
for (int i = 0; i < san_count; i++) {
|
||||||
const GENERAL_NAME* current = sk_GENERAL_NAME_value(san_names, i);
|
const GENERAL_NAME* current = sk_GENERAL_NAME_value(san_names, i);
|
||||||
if (current->type == GEN_DNS) {
|
if (current->type == GEN_DNS) {
|
||||||
const char* dns_name = (const char*)ASN1_STRING_get0_data(current->d.dNSName);
|
const char* dns_name = (const char*)ASN1_STRING_get0_data(current->d.dNSName);
|
||||||
// Safety: ensure no embedded nulls
|
// Safety: ensure no embedded nulls
|
||||||
if (ASN1_STRING_length(current->d.dNSName) == (int)std::strlen(dns_name)) {
|
if (ASN1_STRING_length(current->d.dNSName) == (int)std::strlen(dns_name)) {
|
||||||
names.emplace_back(dns_name);
|
names.emplace_back(dns_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GENERAL_NAMES_free(san_names);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Fallback: Common Name (CN) ---
|
||||||
|
if (names.empty()) {
|
||||||
|
X509_NAME* subject = X509_get_subject_name(cert);
|
||||||
|
if (subject) {
|
||||||
|
int idx = X509_NAME_get_index_by_NID(subject, NID_commonName, -1);
|
||||||
|
if (idx >= 0) {
|
||||||
|
X509_NAME_ENTRY* entry = X509_NAME_get_entry(subject, idx);
|
||||||
|
ASN1_STRING* cn_asn1 = X509_NAME_ENTRY_get_data(entry);
|
||||||
|
const char* cn_str = (const char*)ASN1_STRING_get0_data(cn_asn1);
|
||||||
|
if (ASN1_STRING_length(cn_asn1) == (int)std::strlen(cn_str)) {
|
||||||
|
names.emplace_back(cn_str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GENERAL_NAMES_free(san_names);
|
|
||||||
|
X509_free(cert);
|
||||||
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Fallback: Common Name (CN) ---
|
|
||||||
if (names.empty()) {
|
|
||||||
X509_NAME* subject = X509_get_subject_name(cert);
|
|
||||||
if (subject) {
|
|
||||||
int idx = X509_NAME_get_index_by_NID(subject, NID_commonName, -1);
|
|
||||||
if (idx >= 0) {
|
|
||||||
X509_NAME_ENTRY* entry = X509_NAME_get_entry(subject, idx);
|
|
||||||
ASN1_STRING* cn_asn1 = X509_NAME_ENTRY_get_data(entry);
|
|
||||||
const char* cn_str = (const char*)ASN1_STRING_get0_data(cn_asn1);
|
|
||||||
if (ASN1_STRING_length(cn_asn1) == (int)std::strlen(cn_str)) {
|
|
||||||
names.emplace_back(cn_str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
X509_free(cert);
|
|
||||||
return names;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<uint8_t, crypto_sign_PUBLICKEYBYTES> mPublicKey;
|
std::array<uint8_t, crypto_sign_PUBLICKEYBYTES> mPublicKey;
|
||||||
|
|||||||
@@ -14,16 +14,16 @@
|
|||||||
|
|
||||||
namespace ColumnLynx::Net {
|
namespace ColumnLynx::Net {
|
||||||
struct SessionState {
|
struct SessionState {
|
||||||
SymmetricKey aesKey; // Immutable after creation
|
SymmetricKey aesKey; // Agreed-upon AES-256 kes for that session; Immutable after creation
|
||||||
std::atomic<uint64_t> send_ctr{0}; // Per-direction counters
|
std::atomic<uint64_t> send_ctr{0}; // Per-direction counters
|
||||||
std::atomic<uint64_t> recv_ctr{0};
|
std::atomic<uint64_t> recv_ctr{0}; // Per-direction counters
|
||||||
asio::ip::udp::endpoint udpEndpoint;
|
asio::ip::udp::endpoint udpEndpoint; // Deducted IP + Port of that session client
|
||||||
std::atomic<uint64_t> sendCounter{0};
|
std::atomic<uint64_t> sendCounter{0}; // Counter of sent messages
|
||||||
std::chrono::steady_clock::time_point created = std::chrono::steady_clock::now();
|
std::chrono::steady_clock::time_point created = std::chrono::steady_clock::now(); // Time created
|
||||||
std::chrono::steady_clock::time_point expires{};
|
std::chrono::steady_clock::time_point expires{}; // Time of expiry
|
||||||
uint32_t clientTunIP;
|
uint32_t clientTunIP; // Assigned IP
|
||||||
uint32_t serverTunIP;
|
uint32_t serverTunIP; // Server IP
|
||||||
uint64_t sessionID;
|
uint64_t sessionID; // Session ID
|
||||||
Nonce base_nonce{};
|
Nonce base_nonce{};
|
||||||
|
|
||||||
~SessionState() { sodium_memzero(aesKey.data(), aesKey.size()); }
|
~SessionState() { sodium_memzero(aesKey.data(), aesKey.size()); }
|
||||||
@@ -36,6 +36,7 @@ namespace ColumnLynx::Net {
|
|||||||
expires = created + ttl;
|
expires = created + ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the UDP endpoint
|
||||||
void setUDPEndpoint(const asio::ip::udp::endpoint& ep) {
|
void setUDPEndpoint(const asio::ip::udp::endpoint& ep) {
|
||||||
udpEndpoint = ep;
|
udpEndpoint = ep;
|
||||||
}
|
}
|
||||||
@@ -43,28 +44,31 @@ namespace ColumnLynx::Net {
|
|||||||
|
|
||||||
class SessionRegistry {
|
class SessionRegistry {
|
||||||
public:
|
public:
|
||||||
|
// Return a reference to the Session Registry instance
|
||||||
static SessionRegistry& getInstance() { static SessionRegistry instance; return instance; }
|
static SessionRegistry& getInstance() { static SessionRegistry instance; return instance; }
|
||||||
|
|
||||||
// Insert or replace
|
// Insert or replace a session entry
|
||||||
void put(uint64_t sessionID, std::shared_ptr<SessionState> state) {
|
void put(uint64_t sessionID, std::shared_ptr<SessionState> state) {
|
||||||
std::unique_lock lock(mMutex);
|
std::unique_lock lock(mMutex);
|
||||||
mSessions[sessionID] = std::move(state);
|
mSessions[sessionID] = std::move(state);
|
||||||
mIPSessions[mSessions[sessionID]->clientTunIP] = mSessions[sessionID];
|
mIPSessions[mSessions[sessionID]->clientTunIP] = mSessions[sessionID];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup
|
// Lookup a session entry by session ID
|
||||||
std::shared_ptr<const SessionState> get(uint64_t sessionID) const {
|
std::shared_ptr<const SessionState> get(uint64_t sessionID) const {
|
||||||
std::shared_lock lock(mMutex);
|
std::shared_lock lock(mMutex);
|
||||||
auto it = mSessions.find(sessionID);
|
auto it = mSessions.find(sessionID);
|
||||||
return (it == mSessions.end()) ? nullptr : it->second;
|
return (it == mSessions.end()) ? nullptr : it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lookup a session entry by IPv4
|
||||||
std::shared_ptr<const SessionState> getByIP(uint32_t ip) const {
|
std::shared_ptr<const SessionState> getByIP(uint32_t ip) const {
|
||||||
std::shared_lock lock(mMutex);
|
std::shared_lock lock(mMutex);
|
||||||
auto it = mIPSessions.find(ip);
|
auto it = mIPSessions.find(ip);
|
||||||
return (it == mIPSessions.end()) ? nullptr : it->second;
|
return (it == mIPSessions.end()) ? nullptr : it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get a snapshot of the Session Registry
|
||||||
std::unordered_map<uint64_t, std::shared_ptr<SessionState>> snapshot() const {
|
std::unordered_map<uint64_t, std::shared_ptr<SessionState>> snapshot() const {
|
||||||
std::unordered_map<uint64_t, std::shared_ptr<SessionState>> snap;
|
std::unordered_map<uint64_t, std::shared_ptr<SessionState>> snap;
|
||||||
std::shared_lock lock(mMutex);
|
std::shared_lock lock(mMutex);
|
||||||
@@ -72,7 +76,7 @@ namespace ColumnLynx::Net {
|
|||||||
return snap;
|
return snap;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove
|
// Remove a session by ID
|
||||||
void erase(uint64_t sessionID) {
|
void erase(uint64_t sessionID) {
|
||||||
std::unique_lock lock(mMutex);
|
std::unique_lock lock(mMutex);
|
||||||
mSessions.erase(sessionID);
|
mSessions.erase(sessionID);
|
||||||
@@ -99,6 +103,7 @@ namespace ColumnLynx::Net {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the number of registered sessions
|
||||||
int size() const {
|
int size() const {
|
||||||
std::shared_lock lock(mMutex);
|
std::shared_lock lock(mMutex);
|
||||||
return static_cast<int>(mSessions.size());
|
return static_cast<int>(mSessions.size());
|
||||||
@@ -106,6 +111,7 @@ namespace ColumnLynx::Net {
|
|||||||
|
|
||||||
// IP management (simple for /24 subnet)
|
// IP management (simple for /24 subnet)
|
||||||
|
|
||||||
|
// Get the lowest available IPv4 address; Returns 0 if none available
|
||||||
uint32_t getFirstAvailableIP() const {
|
uint32_t getFirstAvailableIP() const {
|
||||||
std::shared_lock lock(mMutex);
|
std::shared_lock lock(mMutex);
|
||||||
uint32_t baseIP = 0x0A0A0002; // 10.10.0.2
|
uint32_t baseIP = 0x0A0A0002; // 10.10.0.2
|
||||||
@@ -115,15 +121,19 @@ namespace ColumnLynx::Net {
|
|||||||
uint32_t candidateIP = baseIP + offset;
|
uint32_t candidateIP = baseIP + offset;
|
||||||
if (mSessionIPs.find(candidateIP) == mSessionIPs.end()) {
|
if (mSessionIPs.find(candidateIP) == mSessionIPs.end()) {
|
||||||
return candidateIP;
|
return candidateIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0; // Unavailable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lock an IP as assigned to a specific session
|
||||||
void lockIP(uint64_t sessionID, uint32_t ip) {
|
void lockIP(uint64_t sessionID, uint32_t ip) {
|
||||||
std::unique_lock lock(mMutex);
|
std::unique_lock lock(mMutex);
|
||||||
mSessionIPs[sessionID] = ip;
|
mSessionIPs[sessionID] = ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unlock the IP associated with a given session
|
||||||
void deallocIP(uint64_t sessionID) {
|
void deallocIP(uint64_t sessionID) {
|
||||||
std::unique_lock lock(mMutex);
|
std::unique_lock lock(mMutex);
|
||||||
mSessionIPs.erase(sessionID);
|
mSessionIPs.erase(sessionID);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
namespace ColumnLynx::Net::UDP {
|
namespace ColumnLynx::Net::UDP {
|
||||||
|
// @deprecated
|
||||||
// Shared between server and client
|
// Shared between server and client
|
||||||
enum class MessageType : uint8_t {
|
enum class MessageType : uint8_t {
|
||||||
PING = 0x01,
|
PING = 0x01,
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ namespace ColumnLynx::Utils {
|
|||||||
out << "----------------------\n";
|
out << "----------------------\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Panic the main thread and instantly halt execution. This produces a stack trace dump. Do not use by itself, throw an error instead.
|
// Panic the main thread and instantly halt execution. This produces a stack trace dump. Do not use by itself, throw an error instead.
|
||||||
static void panic(const std::string& reason) {
|
static void panic(const std::string& reason) {
|
||||||
std::cerr << "\n***\033[31m MAIN THREAD PANIC! \033[0m***\n";
|
std::cerr << "\n***\033[31m MAIN THREAD PANIC! \033[0m***\n";
|
||||||
std::cerr << "Reason: " << reason << "\n";
|
std::cerr << "Reason: " << reason << "\n";
|
||||||
@@ -204,6 +204,7 @@ namespace ColumnLynx::Utils {
|
|||||||
std::cerr << "Panic trace written to panic_dump.txt\n";
|
std::cerr << "Panic trace written to panic_dump.txt\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gets the current time
|
||||||
static std::string currentTime() {
|
static std::string currentTime() {
|
||||||
std::time_t t = std::time(nullptr);
|
std::time_t t = std::time(nullptr);
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|||||||
@@ -23,12 +23,18 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace ColumnLynx::Utils {
|
namespace ColumnLynx::Utils {
|
||||||
|
// General log function. Use for logging important information.
|
||||||
void log(const std::string &msg);
|
void log(const std::string &msg);
|
||||||
|
// General warning function. Use for logging important warnings.
|
||||||
void warn(const std::string &msg);
|
void warn(const std::string &msg);
|
||||||
|
// General error function. Use for logging failures and general errors.
|
||||||
void error(const std::string &msg);
|
void error(const std::string &msg);
|
||||||
|
// Debug log function. Use for logging non-important information. These will not print unless the binary is compiled with DEBUG=1
|
||||||
void debug(const std::string &msg);
|
void debug(const std::string &msg);
|
||||||
|
|
||||||
|
// Returns the hostname of the running platform.
|
||||||
std::string getHostname();
|
std::string getHostname();
|
||||||
|
// Returns the version of the running release.
|
||||||
std::string getVersion();
|
std::string getVersion();
|
||||||
unsigned short serverPort();
|
unsigned short serverPort();
|
||||||
unsigned char protocolVersion();
|
unsigned char protocolVersion();
|
||||||
@@ -36,6 +42,7 @@ namespace ColumnLynx::Utils {
|
|||||||
|
|
||||||
// Raw byte to hex string conversion helper
|
// Raw byte to hex string conversion helper
|
||||||
std::string bytesToHexString(const uint8_t* bytes, size_t length);
|
std::string bytesToHexString(const uint8_t* bytes, size_t length);
|
||||||
|
// Hex string to raw byte conversion helper
|
||||||
std::vector<uint8_t> hexStringToBytes(const std::string& hex);
|
std::vector<uint8_t> hexStringToBytes(const std::string& hex);
|
||||||
|
|
||||||
// uint8_t to raw string conversion helper
|
// uint8_t to raw string conversion helper
|
||||||
@@ -59,12 +66,14 @@ namespace ColumnLynx::Utils {
|
|||||||
((x & 0xFF00000000000000ULL) >> 56);
|
((x & 0xFF00000000000000ULL) >> 56);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// host -> big-endian (for little-endian hosts) - 64 bit
|
||||||
inline constexpr uint64_t chtobe64(uint64_t x) {
|
inline constexpr uint64_t chtobe64(uint64_t x) {
|
||||||
return cbswap64(x); // host -> big-endian (for little-endian hosts)
|
return cbswap64(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// big-endian -> host (for little-endian hosts) - 64 bit
|
||||||
inline constexpr uint64_t cbe64toh(uint64_t x) {
|
inline constexpr uint64_t cbe64toh(uint64_t x) {
|
||||||
return cbswap64(x); // big-endian -> host (for little-endian hosts)
|
return cbswap64(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the config file in an unordered_map format. This purely reads the config file, you still need to parse it manually.
|
// Returns the config file in an unordered_map format. This purely reads the config file, you still need to parse it manually.
|
||||||
|
|||||||
@@ -33,12 +33,18 @@ namespace ColumnLynx::Net::TCP {
|
|||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start a TCP Connection (Handler for an incoming connection)
|
||||||
void start();
|
void start();
|
||||||
|
// Send a message to the TCP client
|
||||||
void sendMessage(ServerMessageType type, const std::string& data = "");
|
void sendMessage(ServerMessageType type, const std::string& data = "");
|
||||||
|
// Set callback for disconnects
|
||||||
void setDisconnectCallback(std::function<void(std::shared_ptr<TCPConnection>)> cb);
|
void setDisconnectCallback(std::function<void(std::shared_ptr<TCPConnection>)> cb);
|
||||||
|
// Disconnect the client
|
||||||
void disconnect();
|
void disconnect();
|
||||||
|
|
||||||
|
// Get the assigned session ID
|
||||||
uint64_t getSessionID() const;
|
uint64_t getSessionID() const;
|
||||||
|
// Get the assigned AES key; You should probably access this via the Session Registry instead
|
||||||
std::array<uint8_t, 32> getAESKey() const;
|
std::array<uint8_t, 32> getAESKey() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -51,7 +57,9 @@ namespace ColumnLynx::Net::TCP {
|
|||||||
mLastHeartbeatSent(std::chrono::steady_clock::now())
|
mLastHeartbeatSent(std::chrono::steady_clock::now())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// Start the heartbeat routine
|
||||||
void mStartHeartbeat();
|
void mStartHeartbeat();
|
||||||
|
// Handle an incoming TCP message
|
||||||
void mHandleMessage(ClientMessageType type, const std::string& data);
|
void mHandleMessage(ClientMessageType type, const std::string& data);
|
||||||
|
|
||||||
std::shared_ptr<MessageHandler> mHandler;
|
std::shared_ptr<MessageHandler> mHandler;
|
||||||
|
|||||||
@@ -62,10 +62,13 @@ namespace ColumnLynx::Net::TCP {
|
|||||||
mStartAccept();
|
mStartAccept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop the TCP Server
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Start accepting clients via TCP
|
||||||
void mStartAccept();
|
void mStartAccept();
|
||||||
|
|
||||||
asio::io_context &mIoContext;
|
asio::io_context &mIoContext;
|
||||||
asio::ip::tcp::acceptor mAcceptor;
|
asio::ip::tcp::acceptor mAcceptor;
|
||||||
std::unordered_set<TCPConnection::pointer> mClients;
|
std::unordered_set<TCPConnection::pointer> mClients;
|
||||||
|
|||||||
@@ -42,13 +42,18 @@ namespace ColumnLynx::Net::UDP {
|
|||||||
mStartReceive();
|
mStartReceive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop the UDP server
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
// Send UDP data to an endpoint; Fetched via the Session Registry
|
||||||
void sendData(const uint64_t sessionID, const std::string& data);
|
void sendData(const uint64_t sessionID, const std::string& data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Start receiving UDP data
|
||||||
void mStartReceive();
|
void mStartReceive();
|
||||||
|
// Handle an incoming UDP packet
|
||||||
void mHandlePacket(std::size_t bytes);
|
void mHandlePacket(std::size_t bytes);
|
||||||
|
|
||||||
asio::ip::udp::socket mSocket;
|
asio::ip::udp::socket mSocket;
|
||||||
asio::ip::udp::endpoint mRemoteEndpoint;
|
asio::ip::udp::endpoint mRemoteEndpoint;
|
||||||
std::array<uint8_t, 2048> mRecvBuffer; // Adjust size as needed
|
std::array<uint8_t, 2048> mRecvBuffer; // Adjust size as needed
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include <columnlynx/common/net/virtual_interface.hpp>
|
#include <columnlynx/common/net/virtual_interface.hpp>
|
||||||
|
|
||||||
|
// This is all fucking voodoo dark magic.
|
||||||
|
|
||||||
namespace ColumnLynx::Net {
|
namespace ColumnLynx::Net {
|
||||||
// ------------------------------ Constructor ------------------------------
|
// ------------------------------ Constructor ------------------------------
|
||||||
VirtualInterface::VirtualInterface(const std::string& ifName)
|
VirtualInterface::VirtualInterface(const std::string& ifName)
|
||||||
|
|||||||
@@ -196,6 +196,13 @@ namespace ColumnLynx::Net::TCP {
|
|||||||
Nonce symNonce{}; // All zeros
|
Nonce symNonce{}; // All zeros
|
||||||
|
|
||||||
uint32_t clientIP = SessionRegistry::getInstance().getFirstAvailableIP();
|
uint32_t clientIP = SessionRegistry::getInstance().getFirstAvailableIP();
|
||||||
|
|
||||||
|
if (clientIP == 0) {
|
||||||
|
Utils::warn("Out of available IPs! Disconnecting client " + reqAddr);
|
||||||
|
disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Protocol::TunConfig tunConfig{};
|
Protocol::TunConfig tunConfig{};
|
||||||
tunConfig.version = Utils::protocolVersion();
|
tunConfig.version = Utils::protocolVersion();
|
||||||
tunConfig.prefixLength = 24;
|
tunConfig.prefixLength = 24;
|
||||||
|
|||||||
Reference in New Issue
Block a user