High priority and critical issues
This commit is contained in:
@@ -32,7 +32,26 @@ namespace ColumnLynx::Net {
|
||||
|
||||
void SessionRegistry::erase(uint32_t sessionID) {
|
||||
std::unique_lock lock(mMutex);
|
||||
mSessions.erase(sessionID);
|
||||
auto it = mSessions.find(sessionID);
|
||||
if (it != mSessions.end()) {
|
||||
// If the session has a client IP mapping, remove it to avoid stale entries
|
||||
if (it->second) {
|
||||
uint32_t ip = it->second->clientTunIP;
|
||||
auto ipIt = mIPSessions.find(ip);
|
||||
if (ipIt != mIPSessions.end()) {
|
||||
// Only erase if it points to the same session
|
||||
if (ipIt->second == it->second) {
|
||||
mIPSessions.erase(ipIt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any session->ip bookkeeping
|
||||
mSessionIPs.erase(sessionID);
|
||||
|
||||
// Finally erase the session
|
||||
mSessions.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionRegistry::cleanupExpired() {
|
||||
|
||||
@@ -20,10 +20,16 @@ namespace ColumnLynx::Net::TCP {
|
||||
|
||||
auto data = std::make_shared<std::vector<uint8_t>>();
|
||||
data->push_back(typeByte);
|
||||
uint16_t length = payload.size();
|
||||
// Ensure payload fits into protocol's 16-bit length field
|
||||
if (payload.size() > static_cast<size_t>(std::numeric_limits<uint16_t>::max())) {
|
||||
Utils::error("sendMessage(): payload too large (>65535 bytes)");
|
||||
return;
|
||||
}
|
||||
|
||||
data->push_back(length >> 8);
|
||||
data->push_back(length & 0xFF);
|
||||
uint16_t length = static_cast<uint16_t>(payload.size());
|
||||
|
||||
data->push_back(static_cast<uint8_t>(length >> 8));
|
||||
data->push_back(static_cast<uint8_t>(length & 0xFF));
|
||||
|
||||
data->insert(data->end(), payload.begin(), payload.end());
|
||||
auto self = shared_from_this();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Distributed under the terms of the GNU General Public License, either version 2 only or version 3. See LICENSES/ for details.
|
||||
|
||||
#include <columnlynx/common/utils.hpp>
|
||||
#include <filesystem>
|
||||
|
||||
namespace ColumnLynx::Utils {
|
||||
std::string unixMillisToISO8601(uint64_t unixMillis, bool local) {
|
||||
@@ -144,19 +145,49 @@ namespace ColumnLynx::Utils {
|
||||
|
||||
std::vector<std::string> out;
|
||||
|
||||
std::ifstream file(basePath + "whitelisted_keys");
|
||||
namespace fs = std::filesystem;
|
||||
std::error_code ec;
|
||||
|
||||
fs::path base(basePath);
|
||||
fs::path absBase = fs::absolute(base, ec);
|
||||
if (ec) {
|
||||
warn("getWhitelistedKeys(): failed to resolve base path: " + basePath + " - " + ec.message());
|
||||
return out;
|
||||
}
|
||||
|
||||
fs::path whitelist = absBase / "whitelisted_keys";
|
||||
if (!fs::exists(whitelist, ec) || ec) {
|
||||
warn("getWhitelistedKeys(): whitelist file not found: " + whitelist.string());
|
||||
return out;
|
||||
}
|
||||
|
||||
// Canonicalize to avoid symlink tricks
|
||||
fs::path canon = fs::canonical(whitelist, ec);
|
||||
if (ec) {
|
||||
warn("getWhitelistedKeys(): failed to canonicalize path: " + whitelist.string());
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ifstream file(canon);
|
||||
if (!file.is_open()) {
|
||||
warn("Failed to open whitelisted_keys file at path: " + basePath + "whitelisted_keys");
|
||||
warn("getWhitelistedKeys(): failed to open whitelist file: " + canon.string());
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
// Trim whitespace
|
||||
while (!line.empty() && isspace(static_cast<unsigned char>(line.back()))) line.pop_back();
|
||||
size_t start = 0;
|
||||
while (start < line.size() && isspace(static_cast<unsigned char>(line[start]))) ++start;
|
||||
if (start >= line.size()) continue;
|
||||
std::string key = line.substr(start);
|
||||
|
||||
// Convert to upper case to align with the bytesToHexString() output
|
||||
for (int i = 0; i < line.length(); i++) {
|
||||
line[i] = toupper(line[i]);
|
||||
for (size_t i = 0; i < key.length(); ++i) {
|
||||
key[i] = static_cast<char>(toupper(static_cast<unsigned char>(key[i])));
|
||||
}
|
||||
out.push_back(line);
|
||||
out.push_back(key);
|
||||
}
|
||||
|
||||
return out;
|
||||
@@ -166,9 +197,26 @@ namespace ColumnLynx::Utils {
|
||||
// TODO: Currently re-reads every time.
|
||||
std::vector<std::string> readLines;
|
||||
|
||||
std::ifstream file(path);
|
||||
namespace fs = std::filesystem;
|
||||
std::error_code ec;
|
||||
fs::path p(path);
|
||||
fs::path abs = fs::absolute(p, ec);
|
||||
if (ec) {
|
||||
throw std::runtime_error("getConfigMap(): failed to resolve path: " + path + " - " + ec.message());
|
||||
}
|
||||
|
||||
if (!fs::exists(abs, ec) || ec) {
|
||||
throw std::runtime_error("getConfigMap(): config file does not exist: " + abs.string());
|
||||
}
|
||||
|
||||
fs::path canon = fs::canonical(abs, ec);
|
||||
if (ec) {
|
||||
throw std::runtime_error("getConfigMap(): failed to canonicalize config path: " + abs.string());
|
||||
}
|
||||
|
||||
std::ifstream file(canon);
|
||||
if (!file.is_open()) {
|
||||
throw std::runtime_error("Failed to open config file at path: " + path);
|
||||
throw std::runtime_error("Failed to open config file at path: " + canon.string());
|
||||
}
|
||||
|
||||
std::string line;
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
|
||||
#include <columnlynx/common/net/virtual_interface.hpp>
|
||||
|
||||
#include <spawn.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
extern char **environ;
|
||||
|
||||
// This is all fucking voodoo dark magic.
|
||||
|
||||
#if defined(_WIN32)
|
||||
@@ -56,6 +61,33 @@ static void InitializeWintun()
|
||||
#endif // _WIN32
|
||||
|
||||
namespace ColumnLynx::Net {
|
||||
|
||||
// Run a command without invoking a shell. Arguments are passed directly
|
||||
// to the underlying process to avoid shell injection vulnerabilities.
|
||||
static bool runCommand(const std::vector<std::string>& args) {
|
||||
if (args.empty()) return false;
|
||||
|
||||
std::vector<char*> argv;
|
||||
argv.reserve(args.size() + 1);
|
||||
for (const auto &s : args) {
|
||||
argv.push_back(const_cast<char*>(s.c_str()));
|
||||
}
|
||||
argv.push_back(nullptr);
|
||||
|
||||
pid_t pid;
|
||||
int rc = posix_spawnp(&pid, argv[0], nullptr, nullptr, argv.data(), environ);
|
||||
if (rc != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
if (waitpid(pid, &status, 0) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||
}
|
||||
|
||||
// ------------------------------ Constructor ------------------------------
|
||||
VirtualInterface::VirtualInterface(const std::string& ifName)
|
||||
: mIfName(ifName), mFd(-1)
|
||||
@@ -307,25 +339,10 @@ namespace ColumnLynx::Net {
|
||||
|
||||
void VirtualInterface::resetIP() {
|
||||
#if defined(__linux__)
|
||||
char cmd[512];
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"ip addr flush dev %s",
|
||||
mIfName.c_str()
|
||||
);
|
||||
system(cmd);
|
||||
runCommand({"ip", "addr", "flush", "dev", mIfName});
|
||||
#elif defined(__APPLE__)
|
||||
char cmd[512];
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"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);
|
||||
runCommand({"ifconfig", mIfName, "inet", "0.0.0.0", "delete"});
|
||||
runCommand({"ifconfig", mIfName, "inet6", "::", "delete"});
|
||||
|
||||
// Wipe old routes
|
||||
//snprintf(cmd, sizeof(cmd),
|
||||
@@ -357,26 +374,19 @@ namespace ColumnLynx::Net {
|
||||
bool VirtualInterface::mApplyLinuxIP(uint32_t clientIP, uint32_t serverIP,
|
||||
uint8_t prefixLen, uint16_t mtu)
|
||||
{
|
||||
char cmd[512];
|
||||
|
||||
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);
|
||||
runCommand({"ip", "addr", "flush", "dev", mIfName});
|
||||
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"ip addr add %s/%d peer %s dev %s",
|
||||
ipStr.c_str(), prefixLen, peerStr.c_str(), mIfName.c_str());
|
||||
system(cmd);
|
||||
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"ip link set dev %s up mtu %d", mIfName.c_str(), mtu);
|
||||
system(cmd);
|
||||
// Add address with peer
|
||||
std::string addrArg = ipStr + "/" + std::to_string(prefixLen);
|
||||
runCommand({"ip", "addr", "add", addrArg, "peer", peerStr, "dev", mIfName});
|
||||
|
||||
// Bring link up and set MTU
|
||||
runCommand({"ip", "link", "set", "dev", mIfName, "up", "mtu", std::to_string(mtu)});
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -387,39 +397,23 @@ namespace ColumnLynx::Net {
|
||||
bool VirtualInterface::mApplyMacOSIP(uint32_t clientIP, uint32_t serverIP,
|
||||
uint8_t prefixLen, uint16_t mtu)
|
||||
{
|
||||
char cmd[512];
|
||||
|
||||
std::string ipStr = ipv4ToString(clientIP);
|
||||
std::string peerStr = ipv4ToString(serverIP);
|
||||
std::string prefixStr = ipv4ToString(prefixLengthToNetmask(prefixLen), false);
|
||||
Utils::debug("Prefix string: " + prefixStr);
|
||||
|
||||
// Reset
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"ifconfig %s inet 0.0.0.0 delete",
|
||||
mIfName.c_str()
|
||||
);
|
||||
system(cmd);
|
||||
// Reset IPv4 and IPv6 addresses
|
||||
runCommand({"ifconfig", mIfName, "inet", "0.0.0.0", "delete"});
|
||||
runCommand({"ifconfig", mIfName, "inet6", "::", "delete"});
|
||||
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"ifconfig %s inet6 :: delete",
|
||||
mIfName.c_str()
|
||||
);
|
||||
system(cmd);
|
||||
// Set address and netmask
|
||||
std::string netArg = ipStr + " " + peerStr; // ifconfig expects ip peer
|
||||
runCommand({"ifconfig", mIfName, "inet", ipStr, peerStr, "mtu", std::to_string(mtu), "netmask", prefixStr, "up"});
|
||||
|
||||
// Set
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"ifconfig %s inet %s %s mtu %d netmask %s up",
|
||||
mIfName.c_str(), ipStr.c_str(), peerStr.c_str(), mtu, prefixStr.c_str());
|
||||
system(cmd);
|
||||
|
||||
// Host bits are auto-normalized by the kernel on macOS, so we don't need to worry about them not being zeroed out.
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"route -n add -net %s/%d -interface %s",
|
||||
ipStr.c_str(), prefixLen, mIfName.c_str());
|
||||
system(cmd);
|
||||
|
||||
Utils::log("Executed command: " + std::string(cmd));
|
||||
// Add route for the network
|
||||
std::string networkArg = ipStr + "/" + std::to_string(prefixLen);
|
||||
runCommand({"route", "-n", "add", "-net", networkArg, "-interface", mIfName});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user