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.");