From 5e2f32e3eb81cf54bfa192a191500a77dea2cdf2 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 1 Dec 2019 21:50:36 -0800 Subject: [PATCH] Force remote streaming mode if connecting through a VPN --- app/backend/nvcomputer.cpp | 55 ++++++++++++++++++++++++++++++++++++++ app/backend/nvcomputer.h | 3 +++ app/streaming/session.cpp | 15 +++++++++-- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/app/backend/nvcomputer.cpp b/app/backend/nvcomputer.cpp index a6eec12f..a9d3f431 100644 --- a/app/backend/nvcomputer.cpp +++ b/app/backend/nvcomputer.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #define SER_NAME "hostname" #define SER_UUID "uuid" @@ -237,6 +238,60 @@ bool NvComputer::wake() return success; } +bool NvComputer::isReachableOverVpn() +{ + if (activeAddress.isEmpty()) { + return false; + } + + QTcpSocket s; + + s.setProxy(QNetworkProxy::NoProxy); + s.connectToHost(activeAddress, 47984); + if (s.waitForConnected(3000)) { + Q_ASSERT(!s.localAddress().isNull()); + + for (const QNetworkInterface& nic : QNetworkInterface::allInterfaces()) { + // Ensure the interface is up + if ((nic.flags() & QNetworkInterface::IsUp) == 0) { + continue; + } + + for (const QNetworkAddressEntry& addr : nic.addressEntries()) { + if (addr.ip() == s.localAddress()) { + qInfo() << "Found matching interface:" << nic.humanReadableName() << nic.type() << nic.flags(); + + if (nic.flags() & QNetworkInterface::IsPointToPoint) { + // Treat point-to-point links as likely VPNs + return true; + } + + if (nic.type() == QNetworkInterface::Virtual || + nic.type() == QNetworkInterface::Ppp) { + // Treat PPP and virtual interfaces as likely VPNs + return true; + } + +#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) + qInfo() << "MTU is" << nic.maximumTransmissionUnit(); + if (nic.maximumTransmissionUnit() < 1500) { + // Treat MTUs under 1500 as likely VPNs + return true; + } +#endif + + // Didn't meet any of our VPN heuristics + return false; + } + } + } + } + else { + // If we fail to connect, just pretend that it's not a VPN + return false; + } +} + QVector NvComputer::uniqueAddresses() { QVector uniqueAddressList; diff --git a/app/backend/nvcomputer.h b/app/backend/nvcomputer.h index 4da26477..c8524bd4 100644 --- a/app/backend/nvcomputer.h +++ b/app/backend/nvcomputer.h @@ -29,6 +29,9 @@ public: bool wake(); + bool + isReachableOverVpn(); + QVector uniqueAddresses(); diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 40c6ff9f..cc435087 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -356,8 +356,6 @@ bool Session::initialize() m_StreamConfig.fps = m_Preferences->fps; m_StreamConfig.bitrate = m_Preferences->bitrateKbps; m_StreamConfig.hevcBitratePercentageMultiplier = 75; - m_StreamConfig.streamingRemotely = STREAM_CFG_AUTO; - m_StreamConfig.packetSize = 1392; SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Video bitrate: %d kbps", @@ -937,6 +935,19 @@ void Session::exec(int displayOriginX, int displayOriginY) hostInfo.serverInfoGfeVersion = siGfeVersion.data(); } + // isReachableOverVpn() does network I/O, so we only attempt to check + // VPN reachability if we've already contacted the PC successfully + if (m_Computer->isReachableOverVpn()) { + // It looks like our route to this PC is over a VPN. + // Treat it as remote even if the target address is in RFC 1918 address space. + m_StreamConfig.streamingRemotely = STREAM_CFG_REMOTE; + m_StreamConfig.packetSize = 1024; + } + else { + m_StreamConfig.streamingRemotely = STREAM_CFG_AUTO; + m_StreamConfig.packetSize = 1392; + } + int err = LiStartConnection(&hostInfo, &m_StreamConfig, &k_ConnCallbacks, &m_VideoCallbacks, m_AudioDisabled ? nullptr : &m_AudioCallbacks,