Test: proper ipv6 support, still sending v4 to client tun
This commit is contained in:
@@ -34,24 +34,33 @@ namespace ColumnLynx::Net::TCP {
|
|||||||
// Preload the config map
|
// Preload the config map
|
||||||
mRawServerConfig = Utils::getConfigMap("server_config", {"NETWORK", "SUBNET_MASK"});
|
mRawServerConfig = Utils::getConfigMap("server_config", {"NETWORK", "SUBNET_MASK"});
|
||||||
|
|
||||||
asio::error_code ec;
|
asio::error_code ec_open, ec_v6only, ec_bind;
|
||||||
|
|
||||||
if (!ipv4Only) {
|
if (!ipv4Only) {
|
||||||
// Try IPv6 first (dual-stack check)
|
// Try IPv6 (dual-stack if supported)
|
||||||
asio::ip::tcp::endpoint endpoint_v6(asio::ip::tcp::v6(), port);
|
asio::ip::tcp::endpoint endpoint_v6(asio::ip::tcp::v6(), port);
|
||||||
mAcceptor.open(endpoint_v6.protocol(), ec);
|
|
||||||
if (!ec) {
|
mAcceptor.open(endpoint_v6.protocol(), ec_open);
|
||||||
mAcceptor.set_option(asio::ip::v6_only(false), ec); // Allow dual-stack if possible
|
|
||||||
mAcceptor.bind(endpoint_v6, ec);
|
if (!ec_open) {
|
||||||
|
// Try enabling dual-stack, but DO NOT treat failure as fatal
|
||||||
|
mAcceptor.set_option(asio::ip::v6_only(false), ec_v6only);
|
||||||
|
|
||||||
|
// Try binding IPv6
|
||||||
|
mAcceptor.bind(endpoint_v6, ec_bind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to IPv4 if anything failed
|
// If IPv6 bind failed OR IPv6 open failed OR forced IPv4-only
|
||||||
if (ec || ipv4Only) {
|
if (ipv4Only || ec_open || ec_bind) {
|
||||||
Utils::warn("TCP: IPv6 unavailable (" + ec.message() + "), falling back to IPv4 only");
|
if (!ipv4Only)
|
||||||
|
Utils::warn("TCP: IPv6 unavailable (open=" + ec_open.message() +
|
||||||
|
", bind=" + ec_bind.message() +
|
||||||
|
"), falling back to IPv4 only");
|
||||||
|
|
||||||
asio::ip::tcp::endpoint endpoint_v4(asio::ip::tcp::v4(), port);
|
asio::ip::tcp::endpoint endpoint_v4(asio::ip::tcp::v4(), port);
|
||||||
mAcceptor.close(); // ensure clean state
|
|
||||||
|
mAcceptor.close(); // guarantee clean state
|
||||||
mAcceptor.open(endpoint_v4.protocol());
|
mAcceptor.open(endpoint_v4.protocol());
|
||||||
mAcceptor.bind(endpoint_v4);
|
mAcceptor.bind(endpoint_v4);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,24 +16,37 @@ namespace ColumnLynx::Net::UDP {
|
|||||||
UDPServer(asio::io_context& ioContext, uint16_t port, std::shared_ptr<bool> hostRunning, bool ipv4Only = false, std::shared_ptr<VirtualInterface> tun = nullptr)
|
UDPServer(asio::io_context& ioContext, uint16_t port, std::shared_ptr<bool> hostRunning, bool ipv4Only = false, std::shared_ptr<VirtualInterface> tun = nullptr)
|
||||||
: mSocket(ioContext), mHostRunning(hostRunning), mTun(tun)
|
: mSocket(ioContext), mHostRunning(hostRunning), mTun(tun)
|
||||||
{
|
{
|
||||||
asio::error_code ec;
|
asio::error_code ec_open, ec_v6only, ec_bind;
|
||||||
|
|
||||||
if (!ipv4Only) {
|
if (!ipv4Only) {
|
||||||
// Try IPv6 first (dual-stack check)
|
|
||||||
asio::ip::udp::endpoint endpoint_v6(asio::ip::udp::v6(), port);
|
asio::ip::udp::endpoint endpoint_v6(asio::ip::udp::v6(), port);
|
||||||
mSocket.open(endpoint_v6.protocol(), ec);
|
|
||||||
if (!ec) {
|
// Try opening IPv6 socket
|
||||||
mSocket.set_option(asio::ip::v6_only(false), ec); // Allow dual-stack if possible
|
mSocket.open(endpoint_v6.protocol(), ec_open);
|
||||||
mSocket.bind(endpoint_v6, ec);
|
|
||||||
|
if (!ec_open) {
|
||||||
|
// Try enabling dual-stack (non fatal if it fails)
|
||||||
|
mSocket.set_option(asio::ip::v6_only(false), ec_v6only);
|
||||||
|
|
||||||
|
// Attempt bind
|
||||||
|
mSocket.bind(endpoint_v6, ec_bind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to IPv4 if anything failed
|
// Fallback to IPv4 if IPv6 is unusable
|
||||||
if (ec || ipv4Only) {
|
if (ipv4Only || ec_open || ec_bind) {
|
||||||
Utils::warn("UDP: IPv6 unavailable (" + ec.message() + "), falling back to IPv4 only");
|
if (!ipv4Only) {
|
||||||
|
Utils::warn(
|
||||||
|
"UDP: IPv6 unavailable (open=" + ec_open.message() +
|
||||||
|
", bind=" + ec_bind.message() +
|
||||||
|
"), falling back to IPv4 only"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
asio::ip::udp::endpoint endpoint_v4(asio::ip::udp::v4(), port);
|
asio::ip::udp::endpoint endpoint_v4(asio::ip::udp::v4(), port);
|
||||||
mSocket.close(); // ensure clean state
|
|
||||||
|
mSocket.close();
|
||||||
|
mSocket = asio::ip::udp::socket(ioContext); // fully reset internal state
|
||||||
mSocket.open(endpoint_v4.protocol());
|
mSocket.open(endpoint_v4.protocol());
|
||||||
mSocket.bind(endpoint_v4);
|
mSocket.bind(endpoint_v4);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ volatile sig_atomic_t done = 0;
|
|||||||
|
|
||||||
void signalHandler(int signum) {
|
void signalHandler(int signum) {
|
||||||
if (signum == SIGINT || signum == SIGTERM) {
|
if (signum == SIGINT || signum == SIGTERM) {
|
||||||
//log("Received termination signal. Shutting down client.");
|
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,13 +95,17 @@ int main(int argc, char** argv) {
|
|||||||
//ioThread.join();
|
//ioThread.join();
|
||||||
|
|
||||||
log("Client connected to " + host + ":" + port);
|
log("Client connected to " + host + ":" + port);
|
||||||
|
debug("Client connection flag: " + std::to_string(client->isConnected()));
|
||||||
|
debug("Client handshake flag: " + std::to_string(client->isHandshakeComplete()));
|
||||||
|
debug("isDone flag: " + std::to_string(done));
|
||||||
|
|
||||||
// Client is running
|
// Client is running
|
||||||
while ((client->isConnected() || !client->isHandshakeComplete()) && !done) {
|
while ((client->isConnected() || !client->isHandshakeComplete()) && !done) {
|
||||||
|
//debug("Client connection flag: " + std::to_string(client->isConnected()));
|
||||||
auto packet = tun->readPacket();
|
auto packet = tun->readPacket();
|
||||||
if (!client->isConnected() || done) {
|
/*if (!client->isConnected() || done) {
|
||||||
break; // Bail out if connection died or signal set while blocked
|
break; // Bail out if connection died or signal set while blocked
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if (packet.empty()) {
|
if (packet.empty()) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -6,10 +6,41 @@
|
|||||||
|
|
||||||
namespace ColumnLynx::Net::UDP {
|
namespace ColumnLynx::Net::UDP {
|
||||||
void UDPClient::start() {
|
void UDPClient::start() {
|
||||||
// TODO: Add IPv6
|
asio::error_code ec;
|
||||||
auto endpoints = mResolver.resolve(asio::ip::udp::v4(), mHost, mPort);
|
|
||||||
|
// Resolve using an unspecified protocol (allows both IPv4 and IPv6)
|
||||||
|
auto endpoints = mResolver.resolve(
|
||||||
|
asio::ip::udp::v6(), // Try IPv6 first (dual-stack with v4)
|
||||||
|
mHost,
|
||||||
|
mPort,
|
||||||
|
ec
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// If IPv6 fails (host has no AAAA), try IPv4
|
||||||
|
endpoints = mResolver.resolve(
|
||||||
|
asio::ip::udp::v4(),
|
||||||
|
mHost,
|
||||||
|
mPort,
|
||||||
|
ec
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
Utils::error("UDP resolve failed: " + ec.message());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use whichever endpoint resolved
|
||||||
mRemoteEndpoint = *endpoints.begin();
|
mRemoteEndpoint = *endpoints.begin();
|
||||||
mSocket.open(asio::ip::udp::v4());
|
|
||||||
|
// Open socket using the resolved endpoint's protocol
|
||||||
|
mSocket.open(mRemoteEndpoint.protocol(), ec);
|
||||||
|
if (ec) {
|
||||||
|
Utils::error("UDP socket open failed: " + ec.message());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Utils::log("UDP Client ready to send to " + mRemoteEndpoint.address().to_string() + ":" + std::to_string(mRemoteEndpoint.port()));
|
Utils::log("UDP Client ready to send to " + mRemoteEndpoint.address().to_string() + ":" + std::to_string(mRemoteEndpoint.port()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user