diff --git a/CMakeLists.txt b/CMakeLists.txt index e8da7e3..d4e640f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.16) # If MAJOR is 0, and MINOR > 0, Version is BETA project(ColumnLynx - VERSION 0.0.5 + VERSION 0.0.6 LANGUAGES CXX ) @@ -19,7 +19,9 @@ set(CMAKE_CXX_EXTENSIONS OFF) #set(CMAKE_CXX_FLAGS_DEBUG "-g") #add_compile_options(${CMAKE_CXX_FLAGS_DEBUG}) -add_compile_definitions(DEBUG=1) # TODO: Forcing for now, add dymanic based on compile flags later +if(DEBUG) + add_compile_definitions(DEBUG=1) # TODO: Forcing for now, add dymanic based on compile flags later +endif() include(FetchContent) @@ -38,7 +40,7 @@ endif() if(WIN32) add_compile_definitions(_WIN32_WINNT=0x0A00 NOMINMAX WIN32_LEAN_AND_MEAN) elseif(UNIX) - add_compile_options(-Wall -Wextra -Wpedantic) + add_compile_options(-Wall -Wextra -Wpedantic -O3) add_link_options(-pthread) endif() diff --git a/README.md b/README.md index ab93573..034a632 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,16 @@ Configurating the server and client are are relatively easy. Currently (since th - **SERVER_PUBLIC_KEY** (Hex String): The public key to be used - **SERVER_PRIVATE_KEY** (Hex String): The private key to be used +- **NETWORK** (IPv4 Format): The network IPv4 to be used (Server Interface still needs to be configured manually) +- **SUBNET_MASK** (Integer): The subnet mask to be used (ensure proper length, it will not be checked) **Example:** ``` SERVER_PUBLIC_KEY=787B648046F10DDD0B77A6303BE42D859AA65C52F5708CC3C58EB5691F217C7B SERVER_PRIVATE_KEY=778604245F57B847E63BD85DE8208FF1A127FB559895195928C3987E246B77B8787B648046F10DDD0B77A6303BE42D859AA65C52F5708CC3C58EB5691F217C7B +NETWORK=10.10.0.0 +SUBNET_MASK=24 ```
@@ -76,6 +80,8 @@ ColumnLynx makes use of both **TCP** and **UDP**. **TCP** is used for the initia It operates on port **48042** for both TCP and UDP. +Generally, all transmission is done in **little-endian byte order**, since pretty much every single modern architecture uses it by default. The only exemption to this is the **transmission of IP addresses** (for the **Virtual Interface**), which is **big-endian**. + ### Handshake Procedure The handshake between the client and server is done over **TCP**. This is to ensure delivery without much hassle. diff --git a/include/columnlynx/client/net/tcp/tcp_client.hpp b/include/columnlynx/client/net/tcp/tcp_client.hpp index 6d8720c..6778ebd 100644 --- a/include/columnlynx/client/net/tcp/tcp_client.hpp +++ b/include/columnlynx/client/net/tcp/tcp_client.hpp @@ -25,10 +25,10 @@ namespace ColumnLynx::Net::TCP { TCPClient(asio::io_context& ioContext, const std::string& host, const std::string& port, - Utils::LibSodiumWrapper* sodiumWrapper, - std::array* aesKey, - uint64_t* sessionIDRef, - bool* insecureMode, + std::shared_ptr sodiumWrapper, + std::shared_ptr> aesKey, + std::shared_ptr sessionIDRef, + bool insecureMode, std::shared_ptr tun = nullptr) : mResolver(ioContext), @@ -95,12 +95,12 @@ namespace ColumnLynx::Net::TCP { std::string mHost, mPort; uint8_t mServerPublicKey[32]; // Assuming 256-bit public key std::array mSubmittedChallenge{}; - Utils::LibSodiumWrapper* mLibSodiumWrapper; + std::shared_ptr mLibSodiumWrapper; uint64_t mConnectionSessionID; SymmetricKey mConnectionAESKey; - std::array* mGlobalKeyRef; // Reference to global AES key - uint64_t* mSessionIDRef; // Reference to global Session ID - bool* mInsecureMode; // Reference to insecure mode flag + std::shared_ptr> mGlobalKeyRef; // Reference to global AES key + std::shared_ptr mSessionIDRef; // Reference to global Session ID + bool mInsecureMode; // Insecure mode flag asio::steady_timer mHeartbeatTimer; std::chrono::steady_clock::time_point mLastHeartbeatReceived; std::chrono::steady_clock::time_point mLastHeartbeatSent; diff --git a/include/columnlynx/client/net/udp/udp_client.hpp b/include/columnlynx/client/net/udp/udp_client.hpp index 701eb37..86d5a68 100644 --- a/include/columnlynx/client/net/udp/udp_client.hpp +++ b/include/columnlynx/client/net/udp/udp_client.hpp @@ -17,8 +17,8 @@ namespace ColumnLynx::Net::UDP { UDPClient(asio::io_context& ioContext, const std::string& host, const std::string& port, - std::array* aesKeyRef, - uint64_t* sessionIDRef, + std::shared_ptr> aesKeyRef, + std::shared_ptr sessionIDRef, std::shared_ptr tunRef = nullptr) : mSocket(ioContext), mResolver(ioContext), mHost(host), mPort(port), mAesKeyRef(aesKeyRef), mSessionIDRef(sessionIDRef), mTunRef(tunRef) { @@ -43,8 +43,8 @@ namespace ColumnLynx::Net::UDP { asio::ip::udp::endpoint mRemoteEndpoint; std::string mHost; std::string mPort; - std::array* mAesKeyRef; - uint64_t* mSessionIDRef; + std::shared_ptr> mAesKeyRef; + std::shared_ptr mSessionIDRef; std::shared_ptr mTunRef = nullptr; std::array mRecvBuffer; // Adjust size as needed }; diff --git a/include/columnlynx/common/net/session_registry.hpp b/include/columnlynx/common/net/session_registry.hpp index 20939ba..11449ae 100644 --- a/include/columnlynx/common/net/session_registry.hpp +++ b/include/columnlynx/common/net/session_registry.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -109,34 +110,45 @@ namespace ColumnLynx::Net { return static_cast(mSessions.size()); } - // IP management (simple for /24 subnet) + // IP management // Get the lowest available IPv4 address; Returns 0 if none available - uint32_t getFirstAvailableIP() const { + uint32_t getFirstAvailableIP(uint32_t baseIP, uint8_t mask) const { std::shared_lock lock(mMutex); - uint32_t baseIP = 0x0A0A0002; // 10.10.0.2 - // TODO: Expand to support larger subnets - for (uint32_t offset = 0; offset < 254; offset++) { + uint32_t hostCount = (1u << (32 - mask)); + uint32_t firstHost = 2; + uint32_t lastHost = hostCount - 2; + + for (uint32_t offset = firstHost; offset <= lastHost; offset++) { uint32_t candidateIP = baseIP + offset; - if (mSessionIPs.find(candidateIP) == mSessionIPs.end()) { + if (mIPSessions.find(candidateIP) == mIPSessions.end()) { return candidateIP; } } - - return 0; // Unavailable + + return 0; } - // Lock an IP as assigned to a specific session void lockIP(uint64_t sessionID, uint32_t ip) { std::unique_lock lock(mMutex); mSessionIPs[sessionID] = ip; + + /*if (mIPSessions.find(sessionID) == mIPSessions.end()) { + Utils::debug("yikes"); + }*/ + mIPSessions[ip] = mSessions.find(sessionID)->second; } - // Unlock the IP associated with a given session void deallocIP(uint64_t sessionID) { std::unique_lock lock(mMutex); - mSessionIPs.erase(sessionID); + + auto it = mSessionIPs.find(sessionID); + if (it != mSessionIPs.end()) { + uint32_t ip = it->second; + mIPSessions.erase(ip); + mSessionIPs.erase(it); + } } private: diff --git a/include/columnlynx/common/net/virtual_interface.hpp b/include/columnlynx/common/net/virtual_interface.hpp index cf3d2d4..1b19bff 100644 --- a/include/columnlynx/common/net/virtual_interface.hpp +++ b/include/columnlynx/common/net/virtual_interface.hpp @@ -60,6 +60,16 @@ namespace ColumnLynx::Net { return std::string(buf); } + static inline uint32_t stringToIpv4(const std::string &ipStr) { + struct in_addr addr; + + if (inet_pton(AF_INET, ipStr.c_str(), &addr) != 1) { + return 0; // "0.0.0.0" + } + + return ntohl(addr.s_addr); + } + static inline uint32_t prefixLengthToNetmask(uint8_t prefixLen) { if (prefixLen == 0) return 0; uint32_t mask = (0xFFFFFFFF << (32 - prefixLen)) & 0xFFFFFFFF; diff --git a/include/columnlynx/common/utils.hpp b/include/columnlynx/common/utils.hpp index 83ddbec..97014fa 100644 --- a/include/columnlynx/common/utils.hpp +++ b/include/columnlynx/common/utils.hpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #ifdef _WIN32 #include @@ -22,6 +24,10 @@ #include #endif +namespace ColumnLynx { + using IPv6Addr = std::array; +} + namespace ColumnLynx::Utils { // General log function. Use for logging important information. void log(const std::string &msg); @@ -76,6 +82,18 @@ namespace ColumnLynx::Utils { return cbswap64(x); } + template + T cbswap128(const T& x) { + static_assert(sizeof(T) == 16, "cbswap128 requires a 128-bit type"); + + T out{}; + const uint8_t* src = reinterpret_cast(&x); + uint8_t* dst = reinterpret_cast(&out); + std::reverse_copy(src, src + 16, dst); + + return out; + } + // Returns the config file in an unordered_map format. This purely reads the config file, you still need to parse it manually. - std::unordered_map getConfigMap(std::string path); + std::unordered_map getConfigMap(std::string path, std::vector requiredKeys = {}); }; \ No newline at end of file diff --git a/include/columnlynx/server/net/tcp/tcp_connection.hpp b/include/columnlynx/server/net/tcp/tcp_connection.hpp index 53ced26..4b93140 100644 --- a/include/columnlynx/server/net/tcp/tcp_connection.hpp +++ b/include/columnlynx/server/net/tcp/tcp_connection.hpp @@ -17,6 +17,7 @@ #include #include #include +#include namespace ColumnLynx::Net::TCP { class TCPConnection : public std::enable_shared_from_this { @@ -25,10 +26,11 @@ namespace ColumnLynx::Net::TCP { static pointer create( asio::ip::tcp::socket socket, - Utils::LibSodiumWrapper* sodiumWrapper, + std::shared_ptr sodiumWrapper, + std::unordered_map* serverConfig, std::function onDisconnect) { - auto conn = pointer(new TCPConnection(std::move(socket), sodiumWrapper)); + auto conn = pointer(new TCPConnection(std::move(socket), sodiumWrapper, serverConfig)); conn->mOnDisconnect = std::move(onDisconnect); return conn; } @@ -48,10 +50,11 @@ namespace ColumnLynx::Net::TCP { std::array getAESKey() const; private: - TCPConnection(asio::ip::tcp::socket socket, Utils::LibSodiumWrapper* sodiumWrapper) + TCPConnection(asio::ip::tcp::socket socket, std::shared_ptr sodiumWrapper, std::unordered_map* serverConfig) : mHandler(std::make_shared(std::move(socket))), mLibSodiumWrapper(sodiumWrapper), + mRawServerConfig(serverConfig), mHeartbeatTimer(mHandler->socket().get_executor()), mLastHeartbeatReceived(std::chrono::steady_clock::now()), mLastHeartbeatSent(std::chrono::steady_clock::now()) @@ -64,7 +67,8 @@ namespace ColumnLynx::Net::TCP { std::shared_ptr mHandler; std::function)> mOnDisconnect; - Utils::LibSodiumWrapper *mLibSodiumWrapper; + std::shared_ptr mLibSodiumWrapper; + std::unordered_map* mRawServerConfig; std::array mConnectionAESKey; uint64_t mConnectionSessionID; AsymPublicKey mConnectionPublicKey; diff --git a/include/columnlynx/server/net/tcp/tcp_server.hpp b/include/columnlynx/server/net/tcp/tcp_server.hpp index e45e9b6..364a727 100644 --- a/include/columnlynx/server/net/tcp/tcp_server.hpp +++ b/include/columnlynx/server/net/tcp/tcp_server.hpp @@ -24,15 +24,15 @@ namespace ColumnLynx::Net::TCP { public: TCPServer(asio::io_context& ioContext, uint16_t port, - Utils::LibSodiumWrapper* sodiumWrapper, - bool* hostRunning, bool ipv4Only = false) + std::shared_ptr sodiumWrapper, + std::shared_ptr hostRunning, bool ipv4Only = false) : mIoContext(ioContext), mAcceptor(ioContext), mSodiumWrapper(sodiumWrapper), mHostRunning(hostRunning) { // Preload the config map - mRawServerConfig = Utils::getConfigMap("server_config"); + mRawServerConfig = Utils::getConfigMap("server_config", {"NETWORK", "SUBNET_MASK"}); asio::error_code ec; @@ -72,8 +72,8 @@ namespace ColumnLynx::Net::TCP { asio::io_context &mIoContext; asio::ip::tcp::acceptor mAcceptor; std::unordered_set mClients; - Utils::LibSodiumWrapper *mSodiumWrapper; - bool* mHostRunning; + std::shared_ptr mSodiumWrapper; + std::shared_ptr mHostRunning; std::unordered_map mRawServerConfig; }; diff --git a/include/columnlynx/server/net/udp/udp_server.hpp b/include/columnlynx/server/net/udp/udp_server.hpp index 7dfcbe3..f872fa4 100644 --- a/include/columnlynx/server/net/udp/udp_server.hpp +++ b/include/columnlynx/server/net/udp/udp_server.hpp @@ -13,7 +13,7 @@ namespace ColumnLynx::Net::UDP { class UDPServer { public: - UDPServer(asio::io_context& ioContext, uint16_t port, bool* hostRunning, bool ipv4Only = false, std::shared_ptr tun = nullptr) + UDPServer(asio::io_context& ioContext, uint16_t port, std::shared_ptr hostRunning, bool ipv4Only = false, std::shared_ptr tun = nullptr) : mSocket(ioContext), mHostRunning(hostRunning), mTun(tun) { asio::error_code ec; @@ -56,8 +56,8 @@ namespace ColumnLynx::Net::UDP { asio::ip::udp::socket mSocket; asio::ip::udp::endpoint mRemoteEndpoint; - std::array mRecvBuffer; // Adjust size as needed - bool* mHostRunning; + std::array mRecvBuffer; // 2048 seems stable + std::shared_ptr mHostRunning; std::shared_ptr mTun; }; } \ No newline at end of file diff --git a/src/client/main.cpp b/src/client/main.cpp index 7f620dc..feffdaa 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -74,16 +74,17 @@ int main(int argc, char** argv) { std::shared_ptr tun = std::make_shared(optionsObj["interface"].as()); log("Using virtual interface: " + tun->getName()); - LibSodiumWrapper sodiumWrapper = LibSodiumWrapper(); - debug("Public Key: " + Utils::bytesToHexString(sodiumWrapper.getPublicKey(), 32)); - debug("Private Key: " + Utils::bytesToHexString(sodiumWrapper.getPrivateKey(), 64)); + std::shared_ptr sodiumWrapper = std::make_shared(); + debug("Public Key: " + Utils::bytesToHexString(sodiumWrapper->getPublicKey(), 32)); + debug("Private Key: " + Utils::bytesToHexString(sodiumWrapper->getPrivateKey(), 64)); - std::array aesKey = {0}; // Defualt zeroed state until modified by handshake - uint64_t sessionID = 0; + std::shared_ptr> aesKey = std::make_shared>(); + aesKey->fill(0); // Defualt zeroed state until modified by handshake + std::shared_ptr sessionID = std::make_shared(0); asio::io_context io; - auto client = std::make_shared(io, host, port, &sodiumWrapper, &aesKey, &sessionID, &insecureMode, tun); - auto udpClient = std::make_shared(io, host, port, &aesKey, &sessionID, tun); + auto client = std::make_shared(io, host, port, sodiumWrapper, aesKey, sessionID, insecureMode, tun); + auto udpClient = std::make_shared(io, host, port, aesKey, sessionID, tun); client->start(); udpClient->start(); diff --git a/src/client/net/tcp/tcp_client.cpp b/src/client/net/tcp/tcp_client.cpp index 30a97b4..ef03e3a 100644 --- a/src/client/net/tcp/tcp_client.cpp +++ b/src/client/net/tcp/tcp_client.cpp @@ -145,7 +145,7 @@ namespace ColumnLynx::Net::TCP { // Verify pubkey against whitelisted_keys std::vector whitelistedKeys = Utils::getWhitelistedKeys(); 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 (!mInsecureMode) { Utils::error("Server public key not in whitelisted_keys. Terminating connection."); disconnect(); return; diff --git a/src/client/net/udp/udp_client.cpp b/src/client/net/udp/udp_client.cpp index 0fb0ca9..facd53e 100644 --- a/src/client/net/udp/udp_client.cpp +++ b/src/client/net/udp/udp_client.cpp @@ -36,10 +36,9 @@ namespace ColumnLynx::Net::UDP { reinterpret_cast(&hdr), reinterpret_cast(&hdr) + sizeof(UDPPacketHeader) ); - uint64_t sid = *mSessionIDRef; packet.insert(packet.end(), - reinterpret_cast(&sid), - reinterpret_cast(&sid) + sizeof(sid) + reinterpret_cast(mSessionIDRef.get()), + reinterpret_cast(mSessionIDRef.get()) + sizeof(uint64_t) ); packet.insert(packet.end(), encryptedPayload.begin(), encryptedPayload.end()); @@ -90,6 +89,11 @@ 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!"); + return; + } + // Decrypt payload std::vector ciphertext( mRecvBuffer.begin() + sizeof(UDPPacketHeader) + sizeof(uint64_t), diff --git a/src/common/utils.cpp b/src/common/utils.cpp index eff056b..7a1c992 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -49,7 +49,7 @@ namespace ColumnLynx::Utils { } std::string getVersion() { - return "a0.5"; + return "a0.6"; } unsigned short serverPort() { @@ -118,7 +118,7 @@ namespace ColumnLynx::Utils { return out; } - std::unordered_map getConfigMap(std::string path) { + std::unordered_map getConfigMap(std::string path, std::vector requiredKeys) { // TODO: Currently re-reads every time. std::vector readLines; @@ -145,6 +145,14 @@ namespace ColumnLynx::Utils { config.insert({ key, val }); } + if (!requiredKeys.empty()) { + for (std::string x : requiredKeys) { + if (config.find(x) == config.end()) { + throw std::runtime_error("Config doesn't contain all required keys! (Missing: '" + x + "')"); + } + } + } + return config; } } \ No newline at end of file diff --git a/src/common/virtual_interface.cpp b/src/common/virtual_interface.cpp index f6c9666..b19f3a6 100644 --- a/src/common/virtual_interface.cpp +++ b/src/common/virtual_interface.cpp @@ -166,6 +166,13 @@ namespace ColumnLynx::Net { std::string ipStr = ipv4ToString(clientIP); std::string peerStr = ipv4ToString(serverIP); + // Wipe the current config + snprintf(cmd, sizeof(cmd), + "ip addr flush dev %s", + mIfName.c_str() + ); + system(cmd); + snprintf(cmd, sizeof(cmd), "ip addr add %s/%d peer %s dev %s", ipStr.c_str(), prefixLen, peerStr.c_str(), mIfName.c_str()); @@ -190,10 +197,23 @@ namespace ColumnLynx::Net { std::string peerStr = ipv4ToString(serverIP); std::string prefixStr = ipv4ToString(prefixLen); - // Set netmask (/24 CIDR temporarily with raw command, improve later) + // Reset snprintf(cmd, sizeof(cmd), - "ifconfig lynx0 %s %s mtu %d netmask %s up", - ipStr.c_str(), peerStr.c_str(), mtu, prefixStr.c_str()); + "ifconfig %s inet 0.0.0.0 delete", + mIfName.c_str() + ); + system(cmd); + + snprintf(cmd, sizeof(cmd), + "ifconfig %s inet6 :: delete", + mIfName.c_str() + ); + system(cmd); + + // Set + snprintf(cmd, sizeof(cmd), + "ifconfig %s %s %s mtu %d netmask %s up", + mIfName.c_str(), ipStr.c_str(), peerStr.c_str(), mtu, prefixStr.c_str()); system(cmd); Utils::log("Executed command: " + std::string(cmd)); diff --git a/src/server/main.cpp b/src/server/main.cpp index cab6884..3b6214e 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -77,7 +77,7 @@ int main(int argc, char** argv) { log("Using virtual interface: " + tun->getName()); // Generate a temporary keypair, replace with actual CA signed keys later (Note, these are stored in memory) - LibSodiumWrapper sodiumWrapper = LibSodiumWrapper(); + std::shared_ptr sodiumWrapper = std::make_shared(); auto itPubkey = config.find("SERVER_PUBLIC_KEY"); auto itPrivkey = config.find("SERVER_PRIVATE_KEY"); @@ -91,27 +91,26 @@ int main(int argc, char** argv) { std::copy_n(Utils::hexStringToBytes(itPrivkey->second).begin(), sk.size(), sk.begin()); std::copy_n(Utils::hexStringToBytes(itPubkey->second).begin(), pk.size(), pk.begin()); - sodiumWrapper.setKeys(pk, sk); + sodiumWrapper->setKeys(pk, sk); } else { warn("No keypair found in config file! Using random key."); } - log("Server public key: " + bytesToHexString(sodiumWrapper.getPublicKey(), crypto_sign_PUBLICKEYBYTES)); - //log("Server private key: " + bytesToHexString(sodiumWrapper.getPrivateKey(), crypto_sign_SECRETKEYBYTES)); // TEMP, remove later + log("Server public key: " + bytesToHexString(sodiumWrapper->getPublicKey(), crypto_sign_PUBLICKEYBYTES)); - bool hostRunning = true; + std::shared_ptr hostRunning = std::make_shared(true); asio::io_context io; - auto server = std::make_shared(io, serverPort(), &sodiumWrapper, &hostRunning, ipv4Only); - auto udpServer = std::make_shared(io, serverPort(), &hostRunning, ipv4Only, tun); + auto server = std::make_shared(io, serverPort(), sodiumWrapper, hostRunning, ipv4Only); + auto udpServer = std::make_shared(io, serverPort(), hostRunning, ipv4Only, tun); asio::signal_set signals(io, SIGINT, SIGTERM); signals.async_wait([&](const std::error_code&, int) { log("Received termination signal. Shutting down server gracefully."); done = 1; asio::post(io, [&]() { - hostRunning = false; + *hostRunning = false; server->stop(); udpServer->stop(); }); @@ -145,9 +144,6 @@ int main(int argc, char** argv) { } log("Shutting down server..."); - /*hostRunning = false; - server->stop(); - udpServer->stop();*/ io.stop(); if (ioThread.joinable()) { diff --git a/src/server/server/net/tcp/tcp_connection.cpp b/src/server/server/net/tcp/tcp_connection.cpp index 891cf63..34d7094 100644 --- a/src/server/server/net/tcp/tcp_connection.cpp +++ b/src/server/server/net/tcp/tcp_connection.cpp @@ -202,7 +202,18 @@ namespace ColumnLynx::Net::TCP { // Encrypt the Session ID with the established AES key (using symmetric encryption, nonce can be all zeros for this purpose) Nonce symNonce{}; // All zeros - uint32_t clientIP = SessionRegistry::getInstance().getFirstAvailableIP(); + std::string networkString = mRawServerConfig->find("NETWORK")->second; // The load check guarantees that this value exists + uint8_t configMask = std::stoi(mRawServerConfig->find("SUBNET_MASK")->second); // Same deal here + + uint32_t baseIP = Net::VirtualInterface::stringToIpv4(networkString); + + if (baseIP == 0) { + Utils::warn("Your NETWORK value in the server configuration is malformed! I will not be able to accept connections! (Connection " + reqAddr + " was killed)"); + disconnect(); + return; + } + + uint32_t clientIP = SessionRegistry::getInstance().getFirstAvailableIP(baseIP, configMask); if (clientIP == 0) { Utils::warn("Out of available IPs! Disconnecting client " + reqAddr); @@ -214,13 +225,11 @@ namespace ColumnLynx::Net::TCP { tunConfig.version = Utils::protocolVersion(); tunConfig.prefixLength = 24; tunConfig.mtu = 1420; - tunConfig.serverIP = htonl(0x0A0A0001); // 10.10.0.1 - tunConfig.clientIP = htonl(clientIP); // 10.10.0.X + tunConfig.serverIP = htonl(baseIP + 1); // e.g. 10.10.0.1 + tunConfig.clientIP = htonl(clientIP); // e.g. 10.10.0.X tunConfig.dns1 = htonl(0x08080808); // 8.8.8.8 tunConfig.dns2 = 0; - SessionRegistry::getInstance().lockIP(mConnectionSessionID, clientIP); - uint64_t sessionIDNet = Utils::chtobe64(mConnectionSessionID); std::vector payload(sizeof(uint64_t) + sizeof(tunConfig)); @@ -238,6 +247,7 @@ namespace ColumnLynx::Net::TCP { Utils::log("Handshake with " + reqAddr + " completed successfully. Session ID assigned (" + std::to_string(mConnectionSessionID) + ")."); auto session = std::make_shared(mConnectionAESKey, std::chrono::hours(12), clientIP, htonl(0x0A0A0001), mConnectionSessionID); SessionRegistry::getInstance().put(mConnectionSessionID, std::move(session)); + SessionRegistry::getInstance().lockIP(mConnectionSessionID, clientIP); } catch (const std::exception& e) { Utils::error("Failed to decrypt HANDSHAKE_EXCHANGE_KEY from " + reqAddr + ": " + e.what()); diff --git a/src/server/server/net/tcp/tcp_server.cpp b/src/server/server/net/tcp/tcp_server.cpp index 3f71670..05735a9 100644 --- a/src/server/server/net/tcp/tcp_server.cpp +++ b/src/server/server/net/tcp/tcp_server.cpp @@ -31,10 +31,11 @@ namespace ColumnLynx::Net::TCP { mStartAccept(); return; } - + auto client = TCPConnection::create( std::move(socket), mSodiumWrapper, + &mRawServerConfig, [this](std::shared_ptr c) { mClients.erase(c); Utils::log("Client removed.");