diff --git a/client/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp index 4fad4612..3bc6676a 100644 --- a/client/configurators/openvpn_configurator.cpp +++ b/client/configurators/openvpn_configurator.cpp @@ -110,18 +110,24 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig) QJsonObject json = QJsonDocument::fromJson(jsonConfig.toUtf8()).object(); QString config = json[config_key::config].toString(); - if (m_settings->routeMode() != Settings::VpnAllSites) { - config.replace("redirect-gateway def1 bypass-dhcp", ""); + QRegularExpression regex("redirect-gateway.*"); + config.replace(regex, ""); + + if (m_settings->routeMode() == Settings::VpnAllSites) { + config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n"); + // Prevent ipv6 leak + config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n"); + config.append("block-ipv6\n"); } - else { - if(!config.contains("redirect-gateway def1 bypass-dhcp")) { - config.append("redirect-gateway def1 bypass-dhcp\n"); - } + if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { + // no redirect-gateway + } + if (m_settings->routeMode() == Settings::VpnAllExceptSites) { + config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n"); + // Prevent ipv6 leak + config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n"); + config.append("block-ipv6\n"); } - - // Prevent ipv6 leak - config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n"); - config.append("redirect-gateway ipv6\n"); #ifndef MZ_WINDOWS config.replace("block-outside-dns", ""); @@ -146,9 +152,14 @@ QString OpenVpnConfigurator::processConfigWithExportSettings(QString jsonConfig) QJsonObject json = QJsonDocument::fromJson(jsonConfig.toUtf8()).object(); QString config = json[config_key::config].toString(); - if(!config.contains("redirect-gateway def1 bypass-dhcp")) { - config.append("redirect-gateway def1 bypass-dhcp\n"); - } + QRegularExpression regex("redirect-gateway.*"); + config.replace(regex, ""); + + config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n"); + + // Prevent ipv6 leak + config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n"); + config.append("block-ipv6\n"); // remove block-outside-dns for all exported configs config.replace("block-outside-dns", ""); diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index cda802e2..f395b4bc 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -42,6 +42,7 @@ QString OpenVpnProtocol::defaultConfigPath() void OpenVpnProtocol::stop() { qDebug() << "OpenVpnProtocol::stop()"; + setConnectionState(VpnProtocol::Disconnecting); // TODO: need refactoring // sendTermSignal() will even return true while server connected ??? @@ -52,10 +53,10 @@ void OpenVpnProtocol::stop() if (!sendTermSignal()) { killOpenVpnProcess(); } + QThread::msleep(10); m_managementServer.stop(); - qApp->processEvents(); - setConnectionState(VpnProtocol::Disconnecting); } + setConnectionState(VpnProtocol::Disconnected); } ErrorCode OpenVpnProtocol::prepare() @@ -78,11 +79,9 @@ ErrorCode OpenVpnProtocol::prepare() void OpenVpnProtocol::killOpenVpnProcess() { -#ifndef Q_OS_IOS if (m_openVpnProcess){ m_openVpnProcess->close(); } -#endif } void OpenVpnProtocol::readOpenVpnConfiguration(const QJsonObject &configuration) @@ -150,7 +149,6 @@ void OpenVpnProtocol::updateRouteGateway(QString line) ErrorCode OpenVpnProtocol::start() { -#ifndef Q_OS_IOS //qDebug() << "Start OpenVPN connection"; OpenVpnProtocol::stop(); @@ -164,6 +162,27 @@ ErrorCode OpenVpnProtocol::start() return lastError(); } + // Detect default gateway +#ifdef Q_OS_MAC + QProcess p; + p.setProcessChannelMode(QProcess::MergedChannels); + + p.start("route", QStringList() << "-n" << "get" << "default"); + p.waitForFinished(); + QString s = p.readAll(); + + QRegularExpression rx(R"(gateway:\s*(\d+\.\d+\.\d+\.\d+))"); + QRegularExpressionMatch match = rx.match(s); + if (match.hasMatch()) { + m_routeGateway = match.captured(1); + qDebug() << "Set VPN route gateway" << m_routeGateway; + } + else { + qWarning() << "Unable to set VPN route gateway, output:\n" << s; + } +#endif + + // QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log"; // Utils::createEmptyFile(vpnLogFileNamePath); @@ -216,9 +235,6 @@ ErrorCode OpenVpnProtocol::start() //startTimeoutTimer(); return ErrorCode::NoError; -#else - return ErrorCode::NotImplementedError; -#endif } bool OpenVpnProtocol::sendTermSignal() diff --git a/client/ui/pages_logic/SitesLogic.cpp b/client/ui/pages_logic/SitesLogic.cpp index 17357073..96a0fade 100644 --- a/client/ui/pages_logic/SitesLogic.cpp +++ b/client/ui/pages_logic/SitesLogic.cpp @@ -63,14 +63,19 @@ void SitesLogic::onPushButtonAddCustomSitesClicked() m_settings->addVpnSite(mode, newSite, ip); if (!ip.isEmpty()) { - uiLogic()->m_vpnConnection->addRoutes(QStringList() << ip); - uiLogic()->m_vpnConnection->flushDns(); + QMetaObject::invokeMethod(uiLogic()->m_vpnConnection, "addRoutes", + Qt::QueuedConnection, + Q_ARG(QStringList, QStringList() << ip)); } else if (Utils::ipAddressWithSubnetRegExp().exactMatch(newSite)) { - uiLogic()->m_vpnConnection->addRoutes(QStringList() << newSite); - uiLogic()->m_vpnConnection->flushDns(); + QMetaObject::invokeMethod(uiLogic()->m_vpnConnection, "addRoutes", + Qt::QueuedConnection, + Q_ARG(QStringList, QStringList() << newSite)); } + QMetaObject::invokeMethod(uiLogic()->m_vpnConnection, "flushDns", + Qt::QueuedConnection); + onUpdatePage(); }; @@ -116,17 +121,19 @@ void SitesLogic::onPushButtonSitesDeleteClicked(QStringList items) if (!ok || row < 0 || row >= siteModel->rowCount()) return; sites.append(siteModel->data(row, 0).toString()); - if (uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) { + if (uiLogic()->m_vpnConnection && uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) { ips.append(siteModel->data(row, 1).toString()); } } m_settings->removeVpnSites(mode, sites); - if (uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) { - uiLogic()->m_vpnConnection->deleteRoutes(ips); - uiLogic()->m_vpnConnection->flushDns(); - } + QMetaObject::invokeMethod(uiLogic()->m_vpnConnection, "deleteRoutes", + Qt::QueuedConnection, + Q_ARG(QStringList, ips)); + + QMetaObject::invokeMethod(uiLogic()->m_vpnConnection, "flushDns", + Qt::QueuedConnection); onUpdatePage(); } @@ -190,8 +197,12 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName) m_settings->addVpnIps(mode, ips); m_settings->addVpnSites(mode, sites); - uiLogic()->m_vpnConnection->addRoutes(QStringList() << ips); - uiLogic()->m_vpnConnection->flushDns(); + QMetaObject::invokeMethod(uiLogic()->m_vpnConnection, "addRoutes", + Qt::QueuedConnection, + Q_ARG(QStringList, ips)); + + QMetaObject::invokeMethod(uiLogic()->m_vpnConnection, "flushDns", + Qt::QueuedConnection); onUpdatePage(); } diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 57d20127..2b043e33 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -439,7 +439,11 @@ void VpnConnection::disconnectFromVpn() #endif return; } - m_vpnProtocol.data()->stop(); + + if (m_vpnProtocol) { + m_vpnProtocol->deleteLater(); + } + m_vpnProtocol = nullptr; } VpnProtocol::VpnConnectionState VpnConnection::connectionState() @@ -450,10 +454,6 @@ VpnProtocol::VpnConnectionState VpnConnection::connectionState() bool VpnConnection::isConnected() const { -#ifdef Q_OS_IOS - -#endif - if (!m_vpnProtocol.data()) { return false; } diff --git a/client/vpnconnection.h b/client/vpnconnection.h index 8dea7478..63bd4292 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -50,17 +50,12 @@ public: const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); - bool isConnected() const; bool isDisconnected() const; VpnProtocol::VpnConnectionState connectionState(); QSharedPointer vpnProtocol() const; - void addRoutes(const QStringList &ips); - void deleteRoutes(const QStringList &ips); - void flushDns(); - const QString &remoteAddress() const; void addSitesRoutes(const QString &gw, Settings::RouteMode mode); @@ -74,6 +69,11 @@ public slots: void disconnectFromVpn(); + + void addRoutes(const QStringList &ips); + void deleteRoutes(const QStringList &ips); + void flushDns(); + signals: void bytesChanged(quint64 receivedBytes, quint64 sentBytes); void connectionStateChanged(VpnProtocol::VpnConnectionState state); diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index cd959533..e9f57c60 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -18,6 +18,10 @@ IpcServer::IpcServer(QObject *parent): int IpcServer::createPrivilegedProcess() { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::createPrivilegedProcess"; +#endif + m_localpid++; ProcessDescriptor pd(this); @@ -68,31 +72,55 @@ int IpcServer::createPrivilegedProcess() int IpcServer::routeAddList(const QString &gw, const QStringList &ips) { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::routeAddList"; +#endif + return Router::routeAddList(gw, ips); } bool IpcServer::clearSavedRoutes() { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::clearSavedRoutes"; +#endif + return Router::clearSavedRoutes(); } bool IpcServer::routeDeleteList(const QString &gw, const QStringList &ips) { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::routeDeleteList"; +#endif + return Router::routeDeleteList(gw ,ips); } void IpcServer::flushDns() { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::flushDns"; +#endif + return Router::flushDns(); } void IpcServer::resetIpStack() { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::resetIpStack"; +#endif + Router::resetIpStack(); } bool IpcServer::checkAndInstallDriver() { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::checkAndInstallDriver"; +#endif + #ifdef Q_OS_WIN return TapController::checkAndSetup(); #else @@ -102,6 +130,10 @@ bool IpcServer::checkAndInstallDriver() QStringList IpcServer::getTapList() { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::getTapList"; +#endif + #ifdef Q_OS_WIN return TapController::getTapList(); #else @@ -111,13 +143,20 @@ QStringList IpcServer::getTapList() void IpcServer::cleanUp() { +#ifdef MZ_DEBUG qDebug() << "IpcServer::cleanUp"; +#endif + Logger::deinit(); Logger::cleanUp(); } void IpcServer::setLogsEnabled(bool enabled) { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::setLogsEnabled"; +#endif + if (enabled) { Logger::init(); } @@ -128,6 +167,10 @@ void IpcServer::setLogsEnabled(bool enabled) bool IpcServer::copyWireguardConfig(const QString &sourcePath) { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::copyWireguardConfig"; +#endif + #ifdef Q_OS_LINUX const QString wireguardConfigPath = "/etc/wireguard/wg99.conf"; if (QFile::exists(wireguardConfigPath)) @@ -147,6 +190,10 @@ bool IpcServer::copyWireguardConfig(const QString &sourcePath) bool IpcServer::isWireguardRunning() { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::isWireguardRunning"; +#endif + #ifdef Q_OS_LINUX QProcess checkWireguardStatusProcess; @@ -170,5 +217,9 @@ bool IpcServer::isWireguardRunning() bool IpcServer::isWireguardConfigExists(const QString &configPath) { +#ifdef MZ_DEBUG + qDebug() << "IpcServer::isWireguardConfigExists"; +#endif + return QFileInfo::exists(configPath); } diff --git a/service/server/router_linux.cpp b/service/server/router_linux.cpp index 169e9475..3517f8e6 100644 --- a/service/server/router_linux.cpp +++ b/service/server/router_linux.cpp @@ -50,7 +50,6 @@ bool RouterLinux::routeAdd(const QString &ipWithSubnet, const QString &gw, const route.rt_flags = RTF_UP | RTF_GATEWAY; route.rt_metric = 0; - //route.rt_dev = "ens33"; if (int err = ioctl(sock, SIOCADDRT, &route) < 0) { @@ -60,6 +59,8 @@ bool RouterLinux::routeAdd(const QString &ipWithSubnet, const QString &gw, const << " mask " << ((struct sockaddr_in *)&route.rt_genmask)->sin_addr.s_addr << " " << err; return false; } + + m_addedRoutes.append({ipWithSubnet, gw}); return true; } @@ -76,18 +77,23 @@ int RouterLinux::routeAddList(const QString &gw, const QStringList &ips) bool RouterLinux::clearSavedRoutes() { - // No need to delete routes after iface down - return true; - -// int cnt = 0; -// for (const QString &ip: m_addedRoutes) { -// if (routeDelete(ip)) cnt++; -// } - // return (cnt == m_addedRoutes.count()); + int temp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + int cnt = 0; + for (const Route &r: m_addedRoutes) { + if (routeDelete(r.dst, r.gw, temp_sock)) cnt++; + } + bool ret = (cnt == m_addedRoutes.count()); + m_addedRoutes.clear(); + close(temp_sock); + return ret; } bool RouterLinux::routeDelete(const QString &ipWithSubnet, const QString &gw, const int &sock) { +#ifdef MZ_DEBUG + qDebug().noquote() << "RouterMac::routeDelete: " << ipWithSubnet << gw; +#endif + QString ip = Utils::ipAddressFromIpWithSubnet(ipWithSubnet); QString mask = Utils::netMaskFromIpWithSubnet(ipWithSubnet); diff --git a/service/server/router_linux.h b/service/server/router_linux.h index ddd6e28f..6da20b7d 100644 --- a/service/server/router_linux.h +++ b/service/server/router_linux.h @@ -15,6 +15,11 @@ class RouterLinux : public QObject { Q_OBJECT public: + struct Route { + QString dst; + QString gw; + }; + static RouterLinux& Instance(); bool routeAdd(const QString &ip, const QString &gw, const int &sock); @@ -31,7 +36,7 @@ private: RouterLinux(RouterLinux const &) = delete; RouterLinux& operator= (RouterLinux const&) = delete; - QList m_addedRoutes; + QList m_addedRoutes; }; #endif // ROUTERLINUX_H diff --git a/service/server/router_mac.cpp b/service/server/router_mac.cpp index 6de6b99d..f2e88039 100644 --- a/service/server/router_mac.cpp +++ b/service/server/router_mac.cpp @@ -16,6 +16,10 @@ bool RouterMac::routeAdd(const QString &ipWithSubnet, const QString &gw) QString ip = Utils::ipAddressFromIpWithSubnet(ipWithSubnet); QString mask = Utils::netMaskFromIpWithSubnet(ipWithSubnet); +#ifdef MZ_DEBUG + qDebug().noquote() << "RouterMac::routeAdd: " << ipWithSubnet << gw; +#endif + if (!Utils::checkIPv4Format(ip) || !Utils::checkIPv4Format(gw)) { qCritical().noquote() << "Critical, trying to add invalid route: " << ip << gw; return false; @@ -39,7 +43,9 @@ bool RouterMac::routeAdd(const QString &ipWithSubnet, const QString &gw) strcpy(argv[i], parts.at(i).toStdString().c_str()); } + // TODO refactor mainRouteIface(argc, argv); + m_addedRoutes.append({ipWithSubnet, gw}); for (int i = 0; i < argc; i++) { delete [] argv[i]; @@ -59,14 +65,13 @@ int RouterMac::routeAddList(const QString &gw, const QStringList &ips) bool RouterMac::clearSavedRoutes() { - // No need to delete routes after iface down - return true; - -// int cnt = 0; -// for (const QString &ip: m_addedRoutes) { -// if (routeDelete(ip)) cnt++; -// } - // return (cnt == m_addedRoutes.count()); + int cnt = 0; + for (const Route &r: m_addedRoutes) { + if (routeDelete(r.dst, r.gw)) cnt++; + } + bool ret = (cnt == m_addedRoutes.count()); + m_addedRoutes.clear(); + return ret; } bool RouterMac::routeDelete(const QString &ipWithSubnet, const QString &gw) @@ -74,6 +79,10 @@ bool RouterMac::routeDelete(const QString &ipWithSubnet, const QString &gw) QString ip = Utils::ipAddressFromIpWithSubnet(ipWithSubnet); QString mask = Utils::netMaskFromIpWithSubnet(ipWithSubnet); +#ifdef MZ_DEBUG + qDebug().noquote() << "RouterMac::routeDelete: " << ipWithSubnet << gw; +#endif + if (!Utils::checkIPv4Format(ip) || !Utils::checkIPv4Format(gw)) { qCritical().noquote() << "Critical, trying to remove invalid route: " << ip << gw; return false; diff --git a/service/server/router_mac.h b/service/server/router_mac.h index d6e965c5..210918a4 100644 --- a/service/server/router_mac.h +++ b/service/server/router_mac.h @@ -18,6 +18,11 @@ class RouterMac : public QObject public: static RouterMac& Instance(); + struct Route { + QString dst; + QString gw; + }; + bool routeAdd(const QString &ip, const QString &gw); int routeAddList(const QString &gw, const QStringList &ips); bool clearSavedRoutes(); @@ -32,7 +37,7 @@ private: RouterMac(RouterMac const &) = delete; RouterMac& operator= (RouterMac const&) = delete; - QList m_addedRoutes; + QList m_addedRoutes; }; #endif // ROUTERMAC_H