Skip to content

Commit 500c6cf

Browse files
authored
VPN-6632: Fix split tunnel when IPv6 unreachable (#10225) (#10231)
* Compare among IPv6 addresses when starting split tunnelling * Remove firewall rules for SOCKS proxy - not needed anymore * Fix endian conversion bug in WindowsCommons::AdapterIndexTo
1 parent 2f9fdc2 commit 500c6cf

File tree

5 files changed

+77
-46
lines changed

5 files changed

+77
-46
lines changed

src/platforms/windows/daemon/windowsdaemon.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ WindowsDaemon::~WindowsDaemon() {
5151

5252
void WindowsDaemon::prepareActivation(const InterfaceConfig& config) {
5353
// Before creating the interface we need to check which adapter
54-
// routes to the server endpoint
54+
// routes to the server endpoint. This will be selected as the outgoing
55+
// interface for split-tunnelled traffic.
5556
auto serveraddr = QHostAddress(config.m_serverIpv4AddrIn);
5657
m_inetAdapterIndex = WindowsCommons::AdapterIndexTo(serveraddr);
5758
}

src/platforms/windows/daemon/windowsfirewall.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,6 @@ bool WindowsFirewall::enableInterface(int vpnAdapterIndex) {
183183
if (!allowTrafficForAppOnAll(getCurrentPath(), MAX_WEIGHT, msg)) {
184184
return false;
185185
}
186-
msg = "Allow all for socksproxy.exe";
187-
if (!allowTrafficForAppOnAll(getProxyPath(), MAX_WEIGHT, msg)) {
188-
return false;
189-
}
190186
if (!blockTrafficOnPort(53, MED_WEIGHT, "Block all DNS")) {
191187
return false;
192188
}
@@ -830,15 +826,6 @@ QString WindowsFirewall::getCurrentPath() {
830826
return QString::fromLocal8Bit(buffer);
831827
}
832828

833-
QString WindowsFirewall::getProxyPath() {
834-
QString execPath = getCurrentPath();
835-
if (execPath.isEmpty()) {
836-
return "";
837-
}
838-
839-
return QFileInfo(execPath).dir().absoluteFilePath("socksproxy.exe");
840-
}
841-
842829
void WindowsFirewall::importAddress(const QHostAddress& addr,
843830
OUT FWP_VALUE0_& value,
844831
OUT QByteArray* v6DataBuffer) {

src/platforms/windows/daemon/windowsfirewall.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ class WindowsFirewall final : public QObject {
7171

7272
// Utils
7373
QString getCurrentPath();
74-
QString getProxyPath();
7574
void importAddress(const QHostAddress& addr, OUT FWP_VALUE0_& value,
7675
OUT QByteArray* v6DataBuffer);
7776
void importAddress(const QHostAddress& addr, OUT FWP_CONDITION_VALUE0_& value,

src/platforms/windows/daemon/windowssplittunnel.cpp

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44

55
#include "windowssplittunnel.h"
66

7-
#include <qassert.h>
7+
#include <WS2tcpip.h>
8+
#include <iphlpapi.h>
9+
#include <windows.h>
10+
#include <winsock2.h>
11+
#include <ws2ipdef.h>
812

913
#include <memory>
1014

@@ -17,13 +21,13 @@
1721
#include "windowsfirewall.h"
1822

1923
#define PSAPI_VERSION 2
20-
#include <Windows.h>
2124
#include <psapi.h>
2225

2326
#include <QCoreApplication>
2427
#include <QFileInfo>
2528
#include <QNetworkInterface>
2629
#include <QScopeGuard>
30+
#include <QtEndian>
2731

2832
#pragma region
2933

@@ -341,7 +345,7 @@ bool WindowsSplitTunnel::start(int inetAdapterIndex) {
341345

342346
auto config = generateIPConfiguration(inetAdapterIndex);
343347
if (config.empty()) {
344-
logger.error() << "Failed to set Network Config";
348+
logger.error() << "Failed to generate Network Config";
345349
return false;
346350
}
347351
auto ok = DeviceIoControl(m_driver, IOCTL_REGISTER_IP_ADDRESSES, &config[0],
@@ -468,33 +472,76 @@ std::vector<std::byte> WindowsSplitTunnel::generateIPConfiguration(
468472
}
469473
bool WindowsSplitTunnel::getAddress(int adapterIndex, IN_ADDR* out_ipv4,
470474
IN6_ADDR* out_ipv6) {
471-
QNetworkInterface target =
472-
QNetworkInterface::interfaceFromIndex(adapterIndex);
473-
logger.debug() << "Getting adapter info for:" << target.humanReadableName();
475+
MIB_UNICASTIPADDRESS_TABLE* table;
476+
DWORD result = GetUnicastIpAddressTable(AF_UNSPEC, &table);
477+
if (result != NO_ERROR) {
478+
logger.warning() << "GetUnicastIpAddressTable() failed:"
479+
<< WindowsUtils::getErrorMessage(result);
480+
return false;
481+
}
482+
auto guard = qScopeGuard([table]() { FreeMibTable(table); });
483+
484+
// Find the best unicast addresses on this interface.
485+
const MIB_UNICASTIPADDRESS_ROW* bestIpv4 = nullptr;
486+
const MIB_UNICASTIPADDRESS_ROW* bestIpv6 = nullptr;
487+
for (ULONG i = 0; i < table->NumEntries; i++) {
488+
const MIB_UNICASTIPADDRESS_ROW* row = &table->Table[i];
489+
if (row->InterfaceIndex != adapterIndex) {
490+
continue;
491+
}
492+
if (row->SkipAsSource) {
493+
continue;
494+
}
495+
496+
if (row->Address.si_family == AF_INET) {
497+
// Check IPv4 addresses
498+
quint32 rawAddr = row->Address.Ipv4.sin_addr.s_addr;
499+
QHostAddress addr(qFromBigEndian<quint32>(rawAddr));
500+
if (!addr.isGlobal()) {
501+
continue;
502+
}
503+
// Prefer the address with the highest DAD state.
504+
if ((bestIpv4 != nullptr) && (bestIpv4->DadState >= row->DadState)) {
505+
continue;
506+
}
507+
bestIpv4 = row;
508+
} else if (row->Address.si_family == AF_INET6) {
509+
QHostAddress addr(row->Address.Ipv6.sin6_addr.s6_addr);
510+
// Check IPv6 addresses
511+
if (!addr.isGlobal()) {
512+
continue;
513+
}
514+
515+
if (!bestIpv6) {
516+
bestIpv6 = row;
517+
continue;
518+
}
519+
QHostAddress other(bestIpv6->Address.Ipv6.sin6_addr.s6_addr);
474520

475-
auto get = [&target](QAbstractSocket::NetworkLayerProtocol protocol) {
476-
for (auto address : target.addressEntries()) {
477-
if (address.ip().protocol() != protocol) {
521+
// Ignore site-local addresses if a global address is already known.
522+
if (addr.isUniqueLocalUnicast() && !other.isUniqueLocalUnicast()) {
478523
continue;
479524
}
480-
return address.ip().toString().toStdWString();
525+
// Prefer the address with the highest DAD state.
526+
if ((bestIpv6 != nullptr) && (bestIpv6->DadState >= row->DadState)) {
527+
continue;
528+
}
529+
bestIpv6 = row;
481530
}
482-
return std::wstring{};
483-
};
484-
auto ipv4 = get(QAbstractSocket::IPv4Protocol);
485-
auto ipv6 = get(QAbstractSocket::IPv6Protocol);
531+
}
486532

487-
if (InetPtonW(AF_INET, ipv4.c_str(), out_ipv4) != 1) {
488-
logger.debug() << "Ipv4 Conversation error" << WSAGetLastError();
533+
// An IPv4 address is required for split tunnelling.
534+
if (bestIpv4) {
535+
out_ipv4->s_addr = bestIpv4->Address.Ipv4.sin_addr.s_addr;
536+
} else {
489537
return false;
490538
}
491-
if (ipv6.empty()) {
539+
540+
// Output the IPv6 address, if any.
541+
if (bestIpv6) {
542+
std::memcpy(out_ipv6, &bestIpv6->Address.Ipv6.sin6_addr, sizeof(IN6_ADDR));
543+
} else {
492544
std::memset(out_ipv6, 0x00, sizeof(IN6_ADDR));
493-
return true;
494-
}
495-
if (InetPtonW(AF_INET6, ipv6.c_str(), out_ipv6) != 1) {
496-
logger.debug() << "Ipv6 Conversation error" << WSAGetLastError();
497-
return false;
498545
}
499546
return true;
500547
}

src/platforms/windows/windowscommons.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,15 @@ QString WindowsCommons::getTunnelLogFilePath() {
115115
int WindowsCommons::AdapterIndexTo(const QHostAddress& dst) {
116116
logger.debug() << "Getting Current Internet Adapter that routes to"
117117
<< logger.sensitive(dst.toString());
118-
quint32_be ipBigEndian;
119-
quint32 ip = dst.toIPv4Address();
120-
qToBigEndian(ip, &ipBigEndian);
121-
_MIB_IPFORWARDROW routeInfo;
122-
auto result = GetBestRoute(ipBigEndian, 0, &routeInfo);
118+
quint32 ipv4be = qToBigEndian<quint32>(dst.toIPv4Address());
119+
DWORD index = 0;
120+
DWORD result = GetBestInterface(ipv4be, &index);
123121
if (result != NO_ERROR) {
122+
WindowsUtils::windowsLog("Interface lookup failed");
124123
return -1;
125124
}
126-
auto adapter =
127-
QNetworkInterface::interfaceFromIndex(routeInfo.dwForwardIfIndex);
128-
logger.debug() << "Internet Adapter:" << adapter.name();
129-
return routeInfo.dwForwardIfIndex;
125+
logger.debug() << "Internet Adapter:" << index;
126+
return index;
130127
}
131128

132129
// static

0 commit comments

Comments
 (0)