diff --git a/src/client/main.cpp b/src/client/main.cpp index 73efaf9..89e5435 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -182,15 +182,31 @@ int main(int argc, char** argv) { 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 + + // Phase 1: wait for the async TCP connect to succeed (or time out). + // isConnected() is set by the io_context thread once async_connect fires. + { + auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(30); + while (!client->isConnected() && !done) { + if (std::chrono::steady_clock::now() >= deadline) { + error("Connection timed out after 30 seconds."); + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + } + } + + // Phase 2: packet-forwarding loop — runs while the TCP connection is alive. + // sendMessage() in the UDP client already guards against pre-handshake sends + // (it checks AES key / session ID), so entering here before the handshake + // finishes is harmless. while (client->isConnected() && !done) { //debug("Client connection flag: " + std::to_string(client->isConnected())); auto packet = tun->readPacket(); /*if (!client->isConnected() || done) { break; // Bail out if connection died or signal set while blocked }*/ - + if (packet.empty()) { continue; } diff --git a/src/common/virtual_interface.cpp b/src/common/virtual_interface.cpp index d8a3dc7..664409c 100644 --- a/src/common/virtual_interface.cpp +++ b/src/common/virtual_interface.cpp @@ -443,9 +443,26 @@ static bool runCommand(const std::vector& args) { std::string netArg = ipStr + " " + peerStr; // ifconfig expects ip peer runCommand({"ifconfig", mIfName, "inet", ipStr, peerStr, "mtu", std::to_string(mtu), "netmask", prefixStr, "up"}); - // Add route for the network - std::string networkArg = ipStr + "/" + std::to_string(prefixLen); + // Compute the correct network address from the client IP and prefix length. + // Using the raw host IP (ipStr) here would create a host route for 10.10.0.2 + // instead of the intended network route for 10.10.0.0/24, causing traffic + // destined for the peer (10.10.0.1) to miss this route entirely. + uint32_t rawMask = (prefixLen == 0) ? 0u : (0xFFFFFFFFu << (32 - prefixLen)); + uint32_t networkIP = clientIP & rawMask; + std::string networkStr = ipv4ToString(networkIP); + std::string networkArg = networkStr + "/" + std::to_string(prefixLen); + + // Delete stale routes first so we can (re)add cleanly. + // These are best-effort — failure just means the route didn't exist. + runCommand({"route", "-n", "delete", "-net", networkArg}); + runCommand({"route", "-n", "delete", "-host", peerStr}); + + // Add the VPN subnet route. runCommand({"route", "-n", "add", "-net", networkArg, "-interface", mIfName}); + + // Force an explicit host route for the peer so our utun wins over any + // competing /24 route that another tunnel may have installed. + runCommand({"route", "-n", "add", "-host", peerStr, "-interface", mIfName}); return true; } diff --git a/src/server/net/udp/udp_server.cpp b/src/server/net/udp/udp_server.cpp index 71f8766..cf9f2df 100644 --- a/src/server/net/udp/udp_server.cpp +++ b/src/server/net/udp/udp_server.cpp @@ -34,7 +34,7 @@ namespace ColumnLynx::Net::UDP { // Get plaintext session ID (first 4 bytes after header, in network byte order) uint32_t sessionIDNet = 0; std::memcpy(&sessionIDNet, mRecvBuffer.data() + sizeof(UDPPacketHeader), sizeof(uint32_t)); - uint32_t sessionID = sessionIDNet; // ntohl(sessionIDNet); --- IGNORE --- + uint32_t sessionID = ntohl(sessionIDNet); auto it = mRecvBuffer.begin() + sizeof(UDPPacketHeader) + sizeof(uint32_t); std::vector encryptedPayload(it, mRecvBuffer.begin() + bytes);