Compare commits
21 Commits
16cd980c0a
...
b0.3
| Author | SHA1 | Date | |
|---|---|---|---|
| f99036c523 | |||
| 3eadd41a00 | |||
| 8923f45356 | |||
| 471224b043 | |||
| 714aa52f98 | |||
| d5bf741650 | |||
| ae507c3fb9 | |||
| 072fb69a4a | |||
| 6031d9655a | |||
| cb0f674c52 | |||
| a2ecc589f8 | |||
| 33bbd7cce6 | |||
| 640a751f9b | |||
| f9c5c56a1b | |||
| a08dba5b59 | |||
| 17dd504a7a | |||
| 4ba59fb23f | |||
| 9f52bdd54c | |||
| 9e5e728438 | |||
| 29e90938c5 | |||
| d20bee9e60 |
@@ -186,7 +186,7 @@ namespace ColumnLynx::Utils {
|
|||||||
|
|
||||||
// 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 MASTER THREAD PANIC! \033[0m***\n";
|
||||||
std::cerr << "Reason: " << reason << "\n";
|
std::cerr << "Reason: " << reason << "\n";
|
||||||
std::cerr << "Dumping panic trace...\n";
|
std::cerr << "Dumping panic trace...\n";
|
||||||
|
|
||||||
|
|||||||
@@ -76,5 +76,6 @@ namespace ColumnLynx::Net::TCP {
|
|||||||
std::chrono::steady_clock::time_point mLastHeartbeatReceived;
|
std::chrono::steady_clock::time_point mLastHeartbeatReceived;
|
||||||
std::chrono::steady_clock::time_point mLastHeartbeatSent;
|
std::chrono::steady_clock::time_point mLastHeartbeatSent;
|
||||||
int mMissedHeartbeats = 0;
|
int mMissedHeartbeats = 0;
|
||||||
|
std::string mRemoteIP; // Cached remote IP to avoid calling remote_endpoint() on closed sockets
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -327,7 +327,15 @@ namespace ColumnLynx::Net {
|
|||||||
);
|
);
|
||||||
system(cmd);
|
system(cmd);
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
char cmd[256];
|
char cmd[512];
|
||||||
|
// Remove any persistent routes associated with this interface
|
||||||
|
snprintf(cmd, sizeof(cmd),
|
||||||
|
"netsh routing ip delete persistentroute all name=\"%s\"",
|
||||||
|
mIfName.c_str()
|
||||||
|
);
|
||||||
|
system(cmd);
|
||||||
|
|
||||||
|
// Reset to DHCP
|
||||||
snprintf(cmd, sizeof(cmd),
|
snprintf(cmd, sizeof(cmd),
|
||||||
"netsh interface ip set address name=\"%s\" dhcp",
|
"netsh interface ip set address name=\"%s\" dhcp",
|
||||||
mIfName.c_str()
|
mIfName.c_str()
|
||||||
@@ -420,7 +428,11 @@ namespace ColumnLynx::Net {
|
|||||||
uint32_t maskInt = (prefixLen == 0) ? 0 : (0xFFFFFFFF << (32 - prefixLen));
|
uint32_t maskInt = (prefixLen == 0) ? 0 : (0xFFFFFFFF << (32 - prefixLen));
|
||||||
mask = ipv4ToString(maskInt);
|
mask = ipv4ToString(maskInt);
|
||||||
|
|
||||||
char cmd[256];
|
// Calculate network address from IP and mask
|
||||||
|
uint32_t networkInt = (clientIP & maskInt);
|
||||||
|
std::string network = ipv4ToString(networkInt);
|
||||||
|
|
||||||
|
char cmd[512];
|
||||||
|
|
||||||
// 1. Set the static IP + mask + gateway
|
// 1. Set the static IP + mask + gateway
|
||||||
snprintf(cmd, sizeof(cmd),
|
snprintf(cmd, sizeof(cmd),
|
||||||
@@ -436,6 +448,14 @@ namespace ColumnLynx::Net {
|
|||||||
);
|
);
|
||||||
system(cmd);
|
system(cmd);
|
||||||
|
|
||||||
|
// 3. Add route for the VPN network to go through the TUN interface
|
||||||
|
// This is critical: tells Windows to send packets destined for the server/network through the TUN interface
|
||||||
|
snprintf(cmd, sizeof(cmd),
|
||||||
|
"netsh routing ip add persistentroute dest=%s/%d name=\"%s\" nexthopcfg=%s",
|
||||||
|
network.c_str(), prefixLen, mIfName.c_str(), gw.c_str()
|
||||||
|
);
|
||||||
|
system(cmd);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include <asio.hpp>
|
#include <asio.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
#include <columnlynx/common/utils.hpp>
|
#include <columnlynx/common/utils.hpp>
|
||||||
#include <columnlynx/common/panic_handler.hpp>
|
#include <columnlynx/common/panic_handler.hpp>
|
||||||
#include <columnlynx/server/net/tcp/tcp_server.hpp>
|
#include <columnlynx/server/net/tcp/tcp_server.hpp>
|
||||||
@@ -23,22 +25,7 @@ using namespace ColumnLynx;
|
|||||||
|
|
||||||
volatile sig_atomic_t done = 0;
|
volatile sig_atomic_t done = 0;
|
||||||
|
|
||||||
void signalHandler(int signum) {
|
|
||||||
if (signum == SIGINT || signum == SIGTERM) {
|
|
||||||
log("Received termination signal. Shutting down server gracefully.");
|
|
||||||
done = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
// Capture SIGINT and SIGTERM for graceful shutdown
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
struct sigaction action;
|
|
||||||
memset(&action, 0, sizeof(struct sigaction));
|
|
||||||
action.sa_handler = signalHandler;
|
|
||||||
sigaction(SIGINT, &action, nullptr);
|
|
||||||
sigaction(SIGTERM, &action, nullptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cxxopts::Options options("columnlynx_server", "ColumnLynx Server Application");
|
cxxopts::Options options("columnlynx_server", "ColumnLynx Server Application");
|
||||||
|
|
||||||
@@ -67,22 +54,17 @@ int main(int argc, char** argv) {
|
|||||||
bool ipv4Only = optionsObj["ipv4-only"].as<bool>();
|
bool ipv4Only = optionsObj["ipv4-only"].as<bool>();
|
||||||
|
|
||||||
log("ColumnLynx Server, Version " + getVersion());
|
log("ColumnLynx Server, Version " + getVersion());
|
||||||
log("This software is licensed under the GPLv2 only OR the GPLv3. See LICENSES/ for details.");
|
log("This software is licensed under the GPLv2 only OR the GPLv3. See LICENSES/ for details.");
|
||||||
|
|
||||||
|
#if defined(__WIN32__)
|
||||||
|
//WintunInitialize();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> config = Utils::getConfigMap(optionsObj["config"].as<std::string>());
|
||||||
|
|
||||||
std::shared_ptr<VirtualInterface> tun = std::make_shared<VirtualInterface>(optionsObj["interface"].as<std::string>());
|
std::shared_ptr<VirtualInterface> tun = std::make_shared<VirtualInterface>(optionsObj["interface"].as<std::string>());
|
||||||
log("Using virtual interface: " + tun->getName());
|
log("Using virtual interface: " + tun->getName());
|
||||||
|
|
||||||
// Get network configuration from config file
|
|
||||||
std::unordered_map<std::string, std::string> config = Utils::getConfigMap(optionsObj["config"].as<std::string>());
|
|
||||||
std::string networkString = config.find("NETWORK") != config.end() ? config.find("NETWORK")->second : "10.10.0.0";
|
|
||||||
uint8_t subnetMask = config.find("SUBNET_MASK") != config.end() ? std::stoi(config.find("SUBNET_MASK")->second) : 24;
|
|
||||||
uint32_t baseIP = VirtualInterface::stringToIpv4(networkString);
|
|
||||||
uint32_t serverIP = baseIP + 1; // e.g., 10.10.0.1
|
|
||||||
|
|
||||||
// Configure the server's TUN interface
|
|
||||||
tun->configureIP(serverIP, serverIP, subnetMask, 1420);
|
|
||||||
log("Configured TUN interface with IP " + VirtualInterface::ipv4ToString(serverIP) + "/" + std::to_string(subnetMask));
|
|
||||||
|
|
||||||
// Generate a temporary keypair, replace with actual CA signed keys later (Note, these are stored in memory)
|
// Generate a temporary keypair, replace with actual CA signed keys later (Note, these are stored in memory)
|
||||||
std::shared_ptr<LibSodiumWrapper> sodiumWrapper = std::make_shared<LibSodiumWrapper>();
|
std::shared_ptr<LibSodiumWrapper> sodiumWrapper = std::make_shared<LibSodiumWrapper>();
|
||||||
|
|
||||||
@@ -135,6 +117,8 @@ int main(int argc, char** argv) {
|
|||||||
while (!done) {
|
while (!done) {
|
||||||
auto packet = tun->readPacket();
|
auto packet = tun->readPacket();
|
||||||
if (packet.empty()) {
|
if (packet.empty()) {
|
||||||
|
// Small sleep to avoid busy-waiting and to allow signal processing
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,21 +6,28 @@
|
|||||||
|
|
||||||
namespace ColumnLynx::Net::TCP {
|
namespace ColumnLynx::Net::TCP {
|
||||||
void TCPConnection::start() {
|
void TCPConnection::start() {
|
||||||
|
try {
|
||||||
|
// Cache the remote IP early to avoid calling remote_endpoint() on closed sockets later
|
||||||
|
mRemoteIP = mHandler->socket().remote_endpoint().address().to_string();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
mRemoteIP = "unknown";
|
||||||
|
Utils::warn("Failed to get remote endpoint: " + std::string(e.what()));
|
||||||
|
}
|
||||||
|
|
||||||
mHandler->onMessage([this](AnyMessageType type, const std::string& data) {
|
mHandler->onMessage([this](AnyMessageType type, const std::string& data) {
|
||||||
mHandleMessage(static_cast<ClientMessageType>(MessageHandler::toUint8(type)), data);
|
mHandleMessage(static_cast<ClientMessageType>(MessageHandler::toUint8(type)), data);
|
||||||
});
|
});
|
||||||
|
|
||||||
mHandler->onDisconnect([this](const asio::error_code& ec) {
|
mHandler->onDisconnect([this](const asio::error_code& ec) {
|
||||||
// Peer has closed; finalize locally without sending RST
|
// Peer has closed; finalize locally without sending RST
|
||||||
std::string ip = mHandler->socket().remote_endpoint().address().to_string();
|
Utils::log("Client disconnected: " + mRemoteIP + " - " + ec.message());
|
||||||
Utils::log("Client disconnected: " + ip + " - " + ec.message());
|
|
||||||
asio::error_code ec2;
|
asio::error_code ec2;
|
||||||
mHandler->socket().close(ec2);
|
mHandler->socket().close(ec2);
|
||||||
|
|
||||||
SessionRegistry::getInstance().erase(mConnectionSessionID);
|
SessionRegistry::getInstance().erase(mConnectionSessionID);
|
||||||
SessionRegistry::getInstance().deallocIP(mConnectionSessionID);
|
SessionRegistry::getInstance().deallocIP(mConnectionSessionID);
|
||||||
|
|
||||||
Utils::log("Closed connection to " + ip);
|
Utils::log("Closed connection to " + mRemoteIP);
|
||||||
|
|
||||||
if (mOnDisconnect) {
|
if (mOnDisconnect) {
|
||||||
mOnDisconnect(shared_from_this());
|
mOnDisconnect(shared_from_this());
|
||||||
@@ -31,7 +38,7 @@ namespace ColumnLynx::Net::TCP {
|
|||||||
mStartHeartbeat();
|
mStartHeartbeat();
|
||||||
|
|
||||||
// Placeholder for message handling setup
|
// Placeholder for message handling setup
|
||||||
Utils::log("Client connected: " + mHandler->socket().remote_endpoint().address().to_string());
|
Utils::log("Client connected: " + mRemoteIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::sendMessage(ServerMessageType type, const std::string& data) {
|
void TCPConnection::sendMessage(ServerMessageType type, const std::string& data) {
|
||||||
@@ -45,8 +52,6 @@ namespace ColumnLynx::Net::TCP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::disconnect(bool echo) {
|
void TCPConnection::disconnect(bool echo) {
|
||||||
std::string ip = mHandler->socket().remote_endpoint().address().to_string();
|
|
||||||
|
|
||||||
if (echo) {
|
if (echo) {
|
||||||
mHandler->sendMessage(ServerMessageType::GRACEFUL_DISCONNECT, "Server initiated disconnect.");
|
mHandler->sendMessage(ServerMessageType::GRACEFUL_DISCONNECT, "Server initiated disconnect.");
|
||||||
}
|
}
|
||||||
@@ -58,7 +63,7 @@ namespace ColumnLynx::Net::TCP {
|
|||||||
Utils::error("Error during socket shutdown: " + ec.message());
|
Utils::error("Error during socket shutdown: " + ec.message());
|
||||||
}
|
}
|
||||||
// Do not close immediately; final cleanup happens in onDisconnect
|
// Do not close immediately; final cleanup happens in onDisconnect
|
||||||
Utils::log("Initiated graceful disconnect (half-close) to " + ip);
|
Utils::log("Initiated graceful disconnect (half-close) to " + mRemoteIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t TCPConnection::getSessionID() const {
|
uint64_t TCPConnection::getSessionID() const {
|
||||||
@@ -102,7 +107,7 @@ namespace ColumnLynx::Net::TCP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::mHandleMessage(ClientMessageType type, const std::string& data) {
|
void TCPConnection::mHandleMessage(ClientMessageType type, const std::string& data) {
|
||||||
std::string reqAddr = mHandler->socket().remote_endpoint().address().to_string();
|
std::string& reqAddr = mRemoteIP;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ClientMessageType::HANDSHAKE_INIT: {
|
case ClientMessageType::HANDSHAKE_INIT: {
|
||||||
|
|||||||
Reference in New Issue
Block a user