Added basic virtual interface implementation, needs testing. Added Wintun licenses.

This commit is contained in:
2025-11-12 19:14:44 +01:00
parent 5a72895f8d
commit 6fceb84930
8 changed files with 834 additions and 1 deletions

View File

@@ -10,9 +10,11 @@
#include <columnlynx/client/net/tcp/tcp_client.hpp>
#include <columnlynx/client/net/udp/udp_client.hpp>
#include <cxxopts/cxxopts.hpp>
#include <columnlynx/common/net/virtual_interface.hpp>
using asio::ip::tcp;
using namespace ColumnLynx::Utils;
using namespace ColumnLynx::Net;
volatile sig_atomic_t done = 0;
@@ -56,6 +58,13 @@ int main(int argc, char** argv) {
log("ColumnLynx Client, Version " + getVersion());
log("This software is licensed under the GPLv2 only OR the GPLv3. See LICENSES/ for details.");
#if defined(__WIN32__)
WintunInitialize();
#endif
VirtualInterface tun("columnlynxtun0");
log("Using virtual interface: " + tun.getName());
LibSodiumWrapper sodiumWrapper = LibSodiumWrapper();
std::array<uint8_t, 32> aesKey = {0}; // Defualt zeroed state until modified by handshake

View File

@@ -0,0 +1,131 @@
// virtual_interface.cpp - Virtual Interface for Network Communication
// 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.
#include <columnlynx/common/net/virtual_interface.hpp>
namespace ColumnLynx::Net {
// ------------------------------ Constructor ------------------------------
VirtualInterface::VirtualInterface(const std::string& ifName)
: mIfName(ifName), mFd(-1)
{
#if defined(__linux__)
// ---- Linux: /dev/net/tun ----
mFd = open("/dev/net/tun", O_RDWR);
if (mFd < 0)
throw std::runtime_error("Failed to open /dev/net/tun: " + std::string(strerror(errno)));
struct ifreq ifr {};
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
std::strncpy(ifr.ifr_name, ifName.c_str(), IFNAMSIZ);
if (ioctl(mFd, TUNSETIFF, &ifr) < 0) {
close(mFd);
throw std::runtime_error("TUNSETIFF failed: " + std::string(strerror(errno)));
}
#elif defined(__APPLE__)
// ---- macOS: UTUN (system control socket) ----
mFd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if (mFd < 0)
throw std::runtime_error("socket(PF_SYSTEM) failed: " + std::string(strerror(errno)));
struct ctl_info ctlInfo {};
std::strncpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name));
if (ioctl(mFd, CTLIOCGINFO, &ctlInfo) == -1)
throw std::runtime_error("ioctl(CTLIOCGINFO) failed: " + std::string(strerror(errno)));
struct sockaddr_ctl sc {};
sc.sc_len = sizeof(sc);
sc.sc_family = AF_SYSTEM;
sc.ss_sysaddr = AF_SYS_CONTROL;
sc.sc_id = ctlInfo.ctl_id;
sc.sc_unit = 0; // utun0 (0 = auto-assign)
if (connect(mFd, (struct sockaddr*)&sc, sizeof(sc)) < 0)
throw std::runtime_error("connect(AF_SYS_CONTROL) failed: " + std::string(strerror(errno)));
// Retrieve actual utun device name
struct sockaddr_storage addr;
socklen_t addrlen = sizeof(addr);
if (getsockname(mFd, (struct sockaddr*)&addr, &addrlen) == 0) {
const struct sockaddr_ctl* addr_ctl = (const struct sockaddr_ctl*)&addr;
mIfName = "utun" + std::to_string(addr_ctl->sc_unit - 1);
} else {
mIfName = "utunX";
}
#elif defined(_WIN32)
// ---- Windows: Wintun (WireGuard virtual adapter) ----
WINTUN_ADAPTER_HANDLE adapter =
WintunOpenAdapter(L"ColumnLynx", std::wstring(ifName.begin(), ifName.end()).c_str());
if (!adapter)
throw std::runtime_error("Wintun adapter not found or not installed");
WINTUN_SESSION_HANDLE session =
WintunStartSession(adapter, 0x200000); // ring buffer size
if (!session)
throw std::runtime_error("Failed to start Wintun session");
mHandle = WintunGetReadWaitEvent(session);
mFd = -1; // not used on Windows
mIfName = ifName;
#else
throw std::runtime_error("Unsupported platform");
#endif
}
// ------------------------------ Destructor ------------------------------
VirtualInterface::~VirtualInterface() {
#if defined(__linux__) || defined(__APPLE__)
if (mFd >= 0)
close(mFd);
#elif defined(_WIN32)
// Wintun sessions need explicit stop
// (assuming you stored the session handle as member)
// WintunEndSession(mSession);
#endif
}
// ------------------------------ Read ------------------------------
std::vector<uint8_t> VirtualInterface::readPacket() {
#if defined(__linux__) || defined(__APPLE__)
std::vector<uint8_t> buf(4096);
ssize_t n = read(mFd, buf.data(), buf.size());
if (n < 0)
throw std::runtime_error("read() failed: " + std::string(strerror(errno)));
buf.resize(n);
return buf;
#elif defined(_WIN32)
WINTUN_PACKET* packet = WintunReceivePacket(mSession, nullptr);
if (!packet) return {};
std::vector<uint8_t> buf(packet->Data, packet->Data + packet->Length);
WintunReleaseReceivePacket(mSession, packet);
return buf;
#else
return {};
#endif
}
// ------------------------------ Write ------------------------------
void VirtualInterface::writePacket(const std::vector<uint8_t>& packet) {
#if defined(__linux__) || defined(__APPLE__)
ssize_t n = write(mFd, packet.data(), packet.size());
if (n < 0)
throw std::runtime_error("write() failed: " + std::string(strerror(errno)));
#elif defined(_WIN32)
WINTUN_PACKET* tx = WintunAllocateSendPacket(mSession, (DWORD)packet.size());
if (!tx) throw std::runtime_error("WintunAllocateSendPacket failed");
memcpy(tx->Data, packet.data(), packet.size());
WintunSendPacket(mSession, tx);
#endif
}
// ------------------------------ Accessors ------------------------------
const std::string& VirtualInterface::getName() const { return mIfName; }
int VirtualInterface::getFd() const { return mFd; }
}