Compare commits

6 Commits

9 changed files with 52 additions and 18 deletions

View File

@@ -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.3
VERSION 0.0.4
LANGUAGES CXX
)

View File

@@ -49,9 +49,9 @@ namespace ColumnLynx::Net {
const std::string& getName() const;
int getFd() const; // For ASIO integration (on POSIX)
static inline std::string ipToString(uint32_t ip) {
static inline std::string ipv4ToString(uint32_t ip) {
struct in_addr addr;
addr.s_addr = ip; // expected in network byte order
addr.s_addr = htonl(ip);
char buf[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &addr, buf, sizeof(buf)))
@@ -60,6 +60,12 @@ namespace ColumnLynx::Net {
return std::string(buf);
}
static inline uint32_t prefixLengthToNetmask(uint8_t prefixLen) {
if (prefixLen == 0) return 0;
uint32_t mask = (0xFFFFFFFF << (32 - prefixLen)) & 0xFFFFFFFF;
return htonl(mask); // convert to network byte order
}
private:
bool mApplyLinuxIP(uint32_t clientIP, uint32_t serverIP, uint8_t prefixLen, uint16_t mtu);
bool mApplyMacOSIP(uint32_t clientIP, uint32_t serverIP, uint8_t prefixLen, uint16_t mtu);

View File

@@ -38,4 +38,23 @@ namespace ColumnLynx::Utils {
inline std::string uint8ArrayToString(const uint8_t* data, size_t length) {
return std::string(reinterpret_cast<const char*>(data), length);
}
inline constexpr uint64_t bswap64(uint64_t x) {
return ((x & 0x00000000000000FFULL) << 56) |
((x & 0x000000000000FF00ULL) << 40) |
((x & 0x0000000000FF0000ULL) << 24) |
((x & 0x00000000FF000000ULL) << 8) |
((x & 0x000000FF00000000ULL) >> 8) |
((x & 0x0000FF0000000000ULL) >> 24) |
((x & 0x00FF000000000000ULL) >> 40) |
((x & 0xFF00000000000000ULL) >> 56);
}
inline constexpr uint64_t htobe64(uint64_t x) {
return bswap64(x); // host -> big-endian (for little-endian hosts)
}
inline constexpr uint64_t be64toh(uint64_t x) {
return bswap64(x); // big-endian -> host (for little-endian hosts)
}
};

View File

@@ -63,7 +63,7 @@ int main(int argc, char** argv) {
WintunInitialize();
#endif
std::shared_ptr<VirtualInterface> tun = std::make_shared<VirtualInterface>("utun0");
std::shared_ptr<VirtualInterface> tun = std::make_shared<VirtualInterface>("utun1");
log("Using virtual interface: " + tun->getName());
LibSodiumWrapper sodiumWrapper = LibSodiumWrapper();

View File

@@ -247,6 +247,9 @@ namespace ColumnLynx::Net::TCP {
std::memcpy(&mConnectionSessionID, decrypted.data(), sizeof(mConnectionSessionID));
std::memcpy(&mTunConfig, decrypted.data() + sizeof(mConnectionSessionID), sizeof(Protocol::TunConfig));
mConnectionSessionID = Utils::be64toh(mConnectionSessionID);
Utils::log("Connection established with Session ID: " + std::to_string(mConnectionSessionID));
if (mSessionIDRef) { // Copy to the global reference

View File

@@ -37,7 +37,7 @@ namespace ColumnLynx::Utils {
}
std::string getVersion() {
return "a0.3";
return "a0.4";
}
unsigned short serverPort() {

View File

@@ -42,8 +42,11 @@ namespace ColumnLynx::Net {
sc.sc_id = ctlInfo.ctl_id;
sc.sc_unit = 0; // utun0 (0 = auto-assign)
if (connect(mFd, (struct sockaddr*)&sc, sizeof(sc)) < 0)
if (connect(mFd, (struct sockaddr*)&sc, sizeof(sc)) < 0) {
if (errno == EPERM)
throw std::runtime_error("connect(AF_SYS_CONTROL) failed: Insufficient permissions (try running as root)");
throw std::runtime_error("connect(AF_SYS_CONTROL) failed: " + std::string(strerror(errno)));
}
// Retrieve actual utun device name
struct sockaddr_storage addr;
@@ -158,8 +161,8 @@ namespace ColumnLynx::Net {
{
char cmd[512];
std::string ipStr = ipToString(clientIP);
std::string peerStr = ipToString(serverIP);
std::string ipStr = ipv4ToString(clientIP);
std::string peerStr = ipv4ToString(serverIP);
snprintf(cmd, sizeof(cmd),
"ip addr add %s/%d peer %s dev %s",
@@ -181,14 +184,17 @@ namespace ColumnLynx::Net {
{
char cmd[512];
std::string ipStr = ipToString(clientIP);
std::string peerStr = ipToString(serverIP);
std::string ipStr = ipv4ToString(clientIP);
std::string peerStr = ipv4ToString(serverIP);
// Set netmask (/24 CIDR temporarily with raw command, improve later)
snprintf(cmd, sizeof(cmd),
"ifconfig utun0 %s %s mtu %d up",
"ifconfig utun0 %s %s mtu %d netmask 255.255.255.0 up",
ipStr.c_str(), peerStr.c_str(), mtu);
system(cmd);
Utils::log("Executed command: " + std::string(cmd));
return true;
}
@@ -200,8 +206,8 @@ namespace ColumnLynx::Net {
{
#ifdef _WIN32
char ip[32], gw[32];
strcpy(ip, ipToString(clientIP).c_str());
strcpy(gw, ipToString(serverIP).c_str());
strcpy(ip, ipv4ToString(clientIP).c_str());
strcpy(gw, ipv4ToString(serverIP).c_str());
char cmd[256];
snprintf(cmd, sizeof(cmd),

View File

@@ -107,7 +107,7 @@ int main(int argc, char** argv) {
auto session = SessionRegistry::getInstance().getByIP(dstIP);
if (!session) {
Utils::warn("TUN: No session found for destination IP " + VirtualInterface::ipToString(dstIP));
Utils::warn("TUN: No session found for destination IP " + VirtualInterface::ipv4ToString(dstIP));
continue;
}

View File

@@ -173,8 +173,6 @@ namespace ColumnLynx::Net::TCP {
// Make a Session ID
randombytes_buf(&mConnectionSessionID, sizeof(mConnectionSessionID));
// TODO: Make the session ID little-endian for network transmission
// Encrypt the Session ID with the established AES key (using symmetric encryption, nonce can be all zeros for this purpose)
Nonce symNonce{}; // All zeros
@@ -190,8 +188,10 @@ namespace ColumnLynx::Net::TCP {
SessionRegistry::getInstance().lockIP(mConnectionSessionID, clientIP);
uint64_t sessionIDNet = Utils::htobe64(mConnectionSessionID);
std::vector<uint8_t> payload(sizeof(uint64_t) + sizeof(tunConfig));
std::memcpy(payload.data(), &mConnectionSessionID, sizeof(uint64_t));
std::memcpy(payload.data(), &sessionIDNet, sizeof(uint64_t));
std::memcpy(payload.data() + sizeof(uint64_t), &tunConfig, sizeof(tunConfig));
std::vector<uint8_t> encryptedPayload = Utils::LibSodiumWrapper::encryptMessage(