Added a basic TUN, testing the implementation.

This commit is contained in:
2025-11-13 08:31:46 +01:00
parent aebca5cd7e
commit 5c8409b312
15 changed files with 310 additions and 52 deletions

View File

@@ -13,6 +13,8 @@
#include <array>
#include <algorithm>
#include <vector>
#include <columnlynx/common/net/protocol_structs.hpp>
#include <columnlynx/common/net/virtual_interface.hpp>
using asio::ip::tcp;
@@ -25,7 +27,8 @@ namespace ColumnLynx::Net::TCP {
Utils::LibSodiumWrapper* sodiumWrapper,
std::array<uint8_t, 32>* aesKey,
uint64_t* sessionIDRef,
bool* insecureMode)
bool* insecureMode,
VirtualInterface* tun = nullptr)
:
mResolver(ioContext),
mSocket(ioContext),
@@ -70,5 +73,7 @@ namespace ColumnLynx::Net::TCP {
std::chrono::steady_clock::time_point mLastHeartbeatSent;
int mMissedHeartbeats = 0;
bool mIsHostDomain;
Protocol::TunConfig mTunConfig;
VirtualInterface* mTun = nullptr;
};
}

View File

@@ -9,6 +9,7 @@
#include <columnlynx/common/utils.hpp>
#include <columnlynx/common/libsodium_wrapper.hpp>
#include <array>
#include <columnlynx/common/net/virtual_interface.hpp>
namespace ColumnLynx::Net::UDP {
class UDPClient {
@@ -17,8 +18,9 @@ namespace ColumnLynx::Net::UDP {
const std::string& host,
const std::string& port,
std::array<uint8_t, 32>* aesKeyRef,
uint64_t* sessionIDRef)
: mSocket(ioContext), mResolver(ioContext), mHost(host), mPort(port), mAesKeyRef(aesKeyRef), mSessionIDRef(sessionIDRef) { mStartReceive(); }
uint64_t* sessionIDRef,
VirtualInterface* tunRef = nullptr)
: mSocket(ioContext), mResolver(ioContext), mHost(host), mPort(port), mAesKeyRef(aesKeyRef), mSessionIDRef(sessionIDRef), mTunRef(tunRef) { mStartReceive(); }
void start();
void sendMessage(const std::string& data = "");
@@ -35,6 +37,7 @@ namespace ColumnLynx::Net::UDP {
std::string mPort;
std::array<uint8_t, 32>* mAesKeyRef;
uint64_t* mSessionIDRef;
VirtualInterface* mTunRef;
std::array<uint8_t, 2048> mRecvBuffer; // Adjust size as needed
};
}

View File

@@ -0,0 +1,21 @@
// protocol_structs.hpp - Network Protocol Structures
// Copyright (C) 2025 DcruBro
// Distributed under the terms of the GNU General Public License, either version 2 only or version 3. See LICENSES/ for details.
#pragma once
#include <cstdint>
namespace ColumnLynx::Protocol {
#pragma pack(push, 1)
struct TunConfig {
uint8_t version;
uint8_t prefixLength;
uint16_t mtu;
uint32_t serverIP;
uint32_t clientIP;
uint32_t dns1;
uint32_t dns2;
};
#pragma pack(pop)
}

View File

@@ -21,6 +21,9 @@ namespace ColumnLynx::Net {
std::atomic<uint64_t> sendCounter{0};
std::chrono::steady_clock::time_point created = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point expires{};
uint32_t clientTunIP;
uint32_t serverTunIP;
uint64_t sessionID;
Nonce base_nonce{};
~SessionState() { sodium_memzero(aesKey.data(), aesKey.size()); }
@@ -29,7 +32,7 @@ namespace ColumnLynx::Net {
SessionState(SessionState&&) = default;
SessionState& operator=(SessionState&&) = default;
explicit SessionState(const SymmetricKey& k, std::chrono::seconds ttl = std::chrono::hours(24)) : aesKey(k) {
explicit SessionState(const SymmetricKey& k, std::chrono::seconds ttl = std::chrono::hours(24), uint32_t clientIP = 0, uint32_t serverIP = 0, uint64_t id = 0) : aesKey(k), clientTunIP(clientIP), serverTunIP(serverIP), sessionID(id) {
expires = created + ttl;
}
@@ -46,6 +49,7 @@ namespace ColumnLynx::Net {
void put(uint64_t sessionID, std::shared_ptr<SessionState> state) {
std::unique_lock lock(mMutex);
mSessions[sessionID] = std::move(state);
mIPSessions[mSessions[sessionID]->clientTunIP] = mSessions[sessionID];
}
// Lookup
@@ -55,6 +59,12 @@ namespace ColumnLynx::Net {
return (it == mSessions.end()) ? nullptr : it->second;
}
std::shared_ptr<const SessionState> getByIP(uint32_t ip) const {
std::shared_lock lock(mMutex);
auto it = mIPSessions.find(ip);
return (it == mIPSessions.end()) ? nullptr : it->second;
}
std::unordered_map<uint64_t, std::shared_ptr<SessionState>> snapshot() const {
std::unordered_map<uint64_t, std::shared_ptr<SessionState>> snap;
std::shared_lock lock(mMutex);
@@ -79,10 +89,50 @@ namespace ColumnLynx::Net {
++it;
}
}
for (auto it = mIPSessions.begin(); it != mIPSessions.end(); ) {
if (it->second && it->second->expires <= now) {
it = mIPSessions.erase(it);
} else {
++it;
}
}
}
int size() const {
std::shared_lock lock(mMutex);
return static_cast<int>(mSessions.size());
}
// IP management (simple for /24 subnet)
uint32_t getFirstAvailableIP() 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 candidateIP = baseIP + offset;
if (mSessionIPs.find(candidateIP) == mSessionIPs.end()) {
return candidateIP;
}
}
}
void lockIP(uint64_t sessionID, uint32_t ip) {
std::unique_lock lock(mMutex);
mSessionIPs[sessionID] = ip;
}
void deallocIP(uint64_t sessionID) {
std::unique_lock lock(mMutex);
mSessionIPs.erase(sessionID);
}
private:
mutable std::shared_mutex mMutex;
std::unordered_map<uint64_t, std::shared_ptr<SessionState>> mSessions;
std::unordered_map<uint64_t, uint32_t> mSessionIPs;
std::unordered_map<uint32_t, std::shared_ptr<SessionState>> mIPSessions;
};
}

View File

@@ -17,6 +17,7 @@
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <arpa/inet.h>
#elif defined(__APPLE__)
#include <sys/socket.h>
#include <sys/kern_control.h>
@@ -24,8 +25,11 @@
#include <net/if_utun.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <arpa/inet.h>
#elif defined(_WIN32)
#include <windows.h>
#include <ws2tcpip.h>
#include <winsock2.h>
#include <wintun/wintun.h>
#pragma comment(lib, "advapi32.lib")
#endif
@@ -36,12 +40,31 @@ namespace ColumnLynx::Net {
explicit VirtualInterface(const std::string& ifName);
~VirtualInterface();
bool configureIP(uint32_t clientIP, uint32_t serverIP,
uint8_t prefixLen, uint16_t mtu);
std::vector<uint8_t> readPacket();
void writePacket(const std::vector<uint8_t>& packet);
const std::string& getName() const;
int getFd() const; // for ASIO integration (on POSIX)
int getFd() const; // For ASIO integration (on POSIX)
static inline std::string ipToString(uint32_t ip) {
struct in_addr addr;
addr.s_addr = ip; // expected in network byte order
char buf[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &addr, buf, sizeof(buf)))
return "0.0.0.0";
return std::string(buf);
}
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);
bool mApplyWindowsIP(uint32_t clientIP, uint32_t serverIP, uint8_t prefixLen, uint16_t mtu);
std::string mIfName;
int mFd; // POSIX
#if defined(_WIN32)

View File

@@ -16,6 +16,7 @@
#include <columnlynx/common/utils.hpp>
#include <columnlynx/common/libsodium_wrapper.hpp>
#include <columnlynx/common/net/session_registry.hpp>
#include <columnlynx/common/net/protocol_structs.hpp>
namespace ColumnLynx::Net::TCP {
class TCPConnection : public std::enable_shared_from_this<TCPConnection> {

View File

@@ -16,6 +16,7 @@
#include <columnlynx/common/utils.hpp>
#include <columnlynx/server/net/tcp/tcp_connection.hpp>
#include <columnlynx/common/libsodium_wrapper.hpp>
#include <columnlynx/common/net/protocol_structs.hpp>
namespace ColumnLynx::Net::TCP {

View File

@@ -8,12 +8,13 @@
#include <columnlynx/common/net/udp/udp_message_type.hpp>
#include <columnlynx/common/utils.hpp>
#include <array>
#include <columnlynx/common/net/virtual_interface.hpp>
namespace ColumnLynx::Net::UDP {
class UDPServer {
public:
UDPServer(asio::io_context& ioContext, uint16_t port, bool* hostRunning, bool ipv4Only = false)
: mSocket(ioContext), mHostRunning(hostRunning)
UDPServer(asio::io_context& ioContext, uint16_t port, bool* hostRunning, bool ipv4Only = false, VirtualInterface* tun = nullptr)
: mSocket(ioContext), mHostRunning(hostRunning), mTun(tun)
{
asio::error_code ec;
@@ -43,13 +44,15 @@ namespace ColumnLynx::Net::UDP {
void stop();
void sendData(const uint64_t sessionID, const std::string& data);
private:
void mStartReceive();
void mHandlePacket(std::size_t bytes);
void mSendData(const uint64_t sessionID, const std::string& data);
asio::ip::udp::socket mSocket;
asio::ip::udp::endpoint mRemoteEndpoint;
std::array<uint8_t, 2048> mRecvBuffer; // Adjust size as needed
bool* mHostRunning;
VirtualInterface* mTun;
};
}