From 953eca6695b50ba1ddd362cb9eadfbddbd0db50e Mon Sep 17 00:00:00 2001 From: pokamest Date: Tue, 26 Jan 2021 15:01:15 +0300 Subject: [PATCH] Bug fixes: - auto install tap - share connectionState - service crash fix --- client/client.pro | 6 +- client/communicator.cpp | 5 +- client/message.cpp | 13 +- client/message.h | 5 +- client/protocols/openvpnprotocol.cpp | 58 ++++ client/protocols/openvpnprotocol.h | 5 + client/protocols/vpnprotocol.cpp | 10 + client/protocols/vpnprotocol.h | 6 + client/settings.cpp | 30 +- client/settings.h | 13 +- client/ui/mainwindow.cpp | 181 ++++++++-- client/ui/mainwindow.h | 16 +- client/ui/mainwindow.ui | 72 ++-- client/utils.cpp | 68 ++++ client/utils.h | 4 + client/vpnconnection.cpp | 23 ++ client/vpnconnection.h | 4 + deploy/build_windows.bat | 2 +- service/server/localserver.cpp | 49 ++- service/server/localserver.h | 12 +- {client/core => service/server}/router.cpp | 2 +- {client/core => service/server}/router.h | 0 service/server/server.pro | 19 ++ service/server/tapcontroller_win.cpp | 364 +++++++++++++++++++++ service/server/tapcontroller_win.h | 41 +++ 25 files changed, 919 insertions(+), 89 deletions(-) rename {client/core => service/server}/router.cpp (99%) rename {client/core => service/server}/router.h (100%) create mode 100644 service/server/tapcontroller_win.cpp create mode 100644 service/server/tapcontroller_win.h diff --git a/client/client.pro b/client/client.pro index 8e9c0ba3..337ef80c 100644 --- a/client/client.pro +++ b/client/client.pro @@ -14,14 +14,13 @@ HEADERS += \ core/defs.h \ core/errorstrings.h \ core/openvpnconfigurator.h \ - core/router.h \ core/servercontroller.h \ debug.h \ defines.h \ localclient.h \ managementserver.h \ message.h \ - protocols/shadowsocksvpnprotocol.h \ + protocols/shadowsocksvpnprotocol.h \ runguard.h \ settings.h \ ui/Controls/SlidingStackedWidget.h \ @@ -34,14 +33,13 @@ HEADERS += \ SOURCES += \ communicator.cpp \ core/openvpnconfigurator.cpp \ - core/router.cpp \ core/servercontroller.cpp \ debug.cpp \ localclient.cpp \ main.cpp \ managementserver.cpp \ message.cpp \ - protocols/shadowsocksvpnprotocol.cpp \ + protocols/shadowsocksvpnprotocol.cpp \ runguard.cpp \ settings.cpp \ ui/Controls/SlidingStackedWidget.cpp \ diff --git a/client/communicator.cpp b/client/communicator.cpp index 04a4e811..af349a0b 100644 --- a/client/communicator.cpp +++ b/client/communicator.cpp @@ -72,5 +72,8 @@ void Communicator::sendMessage(const Message& message) const QString data = message.toString(); bool status = writeData(data + "\n"); - qDebug().noquote() << QString("Send message '%1', status '%2'").arg(data).arg(Utils::toString(status)); + qDebug().noquote() << QString("Send message '%1',%2 status '%2'"). + arg(static_cast(message.state())). + arg(data). + arg(Utils::toString(status)); } diff --git a/client/message.cpp b/client/message.cpp index eb23cda4..189c0160 100644 --- a/client/message.cpp +++ b/client/message.cpp @@ -22,12 +22,22 @@ QString Message::textState() const case State::Started: return "Started"; case State::FinishRequest: return "FinishRequest"; case State::Finished: return "Finished"; + case State::RoutesAddRequest: return "RoutesAddRequest"; + case State::RouteDeleteRequest: return "RouteDeleteRequest"; + case State::ClearSavedRoutesRequest: return "ClearSavedRoutesRequest"; + case State::FlushDnsRequest: return "FlushDnsRequest"; + case State::InstallDriverRequest: return "InstallDriverRequest"; default: ; } return QString(); } +QString Message::rawData() const +{ + return m_rawData; +} + Message::State Message::state() const { return m_state; @@ -66,6 +76,7 @@ QString Message::argsToString() const Message::Message(const QString& data) { + m_rawData = data; m_valid = false; if (data.isEmpty()) { return; @@ -77,7 +88,7 @@ Message::Message(const QString& data) } bool stateFound = false; - for (int i = static_cast(State::Unknown); i <= static_cast(State::Finished); i++ ) { + for (int i = static_cast(State::Unknown); i <= static_cast(State::InstallDriverRequest); i++ ) { m_state = static_cast(i); if (textState() == dataList.at(0)) { stateFound = true; diff --git a/client/message.h b/client/message.h index 46eed2a5..ea02c656 100644 --- a/client/message.h +++ b/client/message.h @@ -6,7 +6,8 @@ class Message { public: - enum class State {Unknown, Initialize, StartRequest, Started, FinishRequest, Finished}; + enum class State {Unknown, Initialize, StartRequest, Started, FinishRequest, Finished, + RoutesAddRequest, RouteDeleteRequest, ClearSavedRoutesRequest, FlushDnsRequest, InstallDriverRequest}; Message(State state, const QStringList& args); Message(const QString& data); @@ -16,6 +17,7 @@ public: QStringList args() const; State state() const; bool isValid() const; + QString rawData() const; protected: QString textState() const; @@ -26,6 +28,7 @@ protected: bool m_valid; State m_state; QStringList m_args; + QString m_rawData; }; #endif // MESSAGE_H diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index c290e13d..37d1b77e 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include "communicator.h" @@ -106,6 +108,15 @@ void OpenVpnProtocol::writeCommand(const QString& command) } } +void OpenVpnProtocol::updateRouteGateway(QString line) +{ + line = line.split("ROUTE_GATEWAY", QString::SkipEmptyParts).at(1); + if (!line.contains("/")) return; + m_routeGateway = line.split("/", QString::SkipEmptyParts).first(); + m_routeGateway.replace(" ", ""); + qDebug() << "Set VPN route gateway" << m_routeGateway; +} + QString OpenVpnProtocol::openVpnExecPath() const { #ifdef Q_OS_WIN @@ -209,6 +220,7 @@ void OpenVpnProtocol::onReadyReadDataFromManagementServer() if (line.contains("CONNECTED,SUCCESS")) { sendByteCount(); stopTimeoutTimer(); + updateVpnGateway(); setConnectionState(VpnProtocol::ConnectionState::Connected); continue; } else if (line.contains("EXITING,SIGTER")) { @@ -220,6 +232,10 @@ void OpenVpnProtocol::onReadyReadDataFromManagementServer() } } + if (line.contains("ROUTE_GATEWAY")) { + updateRouteGateway(line); + } + if (line.contains("FATAL")) { if (line.contains("tap-windows6 adapters on this system are currently in use or disabled")) { emit protocolError(ErrorCode::OpenVpnAdaptersInUseError); @@ -259,4 +275,46 @@ void OpenVpnProtocol::onOpenVpnProcessFinished(int exitCode) setConnectionState(VpnProtocol::ConnectionState::Disconnected); } +void OpenVpnProtocol::updateVpnGateway() +{ + QProcess ipconfig; + ipconfig.start("ipconfig", QStringList() << "/all"); + ipconfig.waitForStarted(); + ipconfig.waitForFinished(); + QString d = ipconfig.readAll(); + d.replace("\r", ""); + //qDebug().noquote() << d; + + QStringList adapters = d.split(":\n"); + + bool isTapV9Present = false; + QString tapV9; + for (int i = 0; i < adapters.size(); ++i) { + if (adapters.at(i).contains("TAP-Windows Adapter V9")) { + isTapV9Present = true; + tapV9 = adapters.at(i); + break; + } + } + if (!isTapV9Present) { + m_vpnGateway = ""; + } + + QStringList lines = tapV9.split("\n"); + for (int i = 0; i < lines.size(); ++i) { + if (!lines.at(i).contains("DHCP")) continue; + + QRegularExpression re("(: )([\\d\\.]+)($)"); + QRegularExpressionMatch match = re.match(lines.at(i)); + + if (match.hasMatch()) { + qDebug().noquote() << "Current VPN Gateway IP Address: " << match.captured(0); + m_vpnGateway = match.captured(2); + return; + } + else continue; + } + + m_vpnGateway = ""; +} diff --git a/client/protocols/openvpnprotocol.h b/client/protocols/openvpnprotocol.h index 84f7709d..3fe8b21e 100644 --- a/client/protocols/openvpnprotocol.h +++ b/client/protocols/openvpnprotocol.h @@ -46,6 +46,11 @@ protected: QString m_configFileName; QTimer m_openVpnStateSigTermHandlerTimer; bool m_requestFromUserToStop; + + +private: + void updateRouteGateway(QString line); + void updateVpnGateway(); }; #endif // OPENVPNPROTOCOL_H diff --git a/client/protocols/vpnprotocol.cpp b/client/protocols/vpnprotocol.cpp index fc9cbc79..8119e67e 100644 --- a/client/protocols/vpnprotocol.cpp +++ b/client/protocols/vpnprotocol.cpp @@ -94,6 +94,16 @@ void VpnProtocol::setConnectionState(VpnProtocol::ConnectionState state) emit connectionStateChanged(m_connectionState); } +QString VpnProtocol::vpnGateway() const +{ + return m_vpnGateway; +} + +QString VpnProtocol::routeGateway() const +{ + return m_routeGateway; +} + QString VpnProtocol::textConnectionState(ConnectionState connectionState) { switch (connectionState) { diff --git a/client/protocols/vpnprotocol.h b/client/protocols/vpnprotocol.h index fa1fc9a9..a9cc1331 100644 --- a/client/protocols/vpnprotocol.h +++ b/client/protocols/vpnprotocol.h @@ -35,6 +35,9 @@ public: QString textConnectionState() const; void setLastError(ErrorCode lastError); + QString routeGateway() const; + QString vpnGateway() const; + signals: void bytesChanged(quint64 receivedBytes, quint64 sentBytes); void connectionStateChanged(VpnProtocol::ConnectionState state); @@ -54,12 +57,15 @@ protected: static Communicator* m_communicator; ConnectionState m_connectionState; + QString m_routeGateway; + QString m_vpnGateway; private: QTimer* m_timeoutTimer; ErrorCode m_lastError; quint64 m_receivedBytes; quint64 m_sentBytes; + }; #endif // VPNPROTOCOL_H diff --git a/client/settings.cpp b/client/settings.cpp index e0062c2b..5fdc23a0 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -1,32 +1,32 @@ -#include #include "defines.h" #include "settings.h" -Settings::Settings(QObject* parent) : QObject(parent) +Settings::Settings(QObject* parent) : + QObject(parent), + m_settings (ORGANIZATION_NAME, APPLICATION_NAME, this) { - m_settings = new QSettings(ORGANIZATION_NAME, APPLICATION_NAME, this); read(); } void Settings::read() { - m_settings->beginGroup("Server"); - m_userName = m_settings->value("userName", QString()).toString(); - m_password = m_settings->value("password", QString()).toString(); - m_serverName = m_settings->value("serverName", QString()).toString(); - m_serverPort = m_settings->value("serverPort", 22).toInt(); - m_settings->endGroup(); + m_settings.beginGroup("Server"); + m_userName = m_settings.value("userName", QString()).toString(); + m_password = m_settings.value("password", QString()).toString(); + m_serverName = m_settings.value("serverName", QString()).toString(); + m_serverPort = m_settings.value("serverPort", 22).toInt(); + m_settings.endGroup(); } void Settings::save() { - m_settings->beginGroup("Server"); - m_settings->setValue("userName", m_userName); - m_settings->setValue("password", m_password); - m_settings->setValue("serverName", m_serverName); - m_settings->setValue("serverPort", m_serverPort); - m_settings->endGroup(); + m_settings.beginGroup("Server"); + m_settings.setValue("userName", m_userName); + m_settings.setValue("password", m_password); + m_settings.setValue("serverName", m_serverName); + m_settings.setValue("serverPort", m_serverPort); + m_settings.endGroup(); } bool Settings::haveAuthData() const diff --git a/client/settings.h b/client/settings.h index 13177e30..1feb8d00 100644 --- a/client/settings.h +++ b/client/settings.h @@ -3,6 +3,7 @@ #include #include +#include #include "core/defs.h" @@ -35,8 +36,18 @@ public: bool haveAuthData() const; + + // list of sites to pass blocking added by user + QStringList customSites() { return m_settings.value("customSites").toStringList(); } + void setCustomSites(const QStringList &customSites) { m_settings.setValue("customSites", customSites); } + + // list of ips to pass blocking generated from customSites + QStringList customIps() { return m_settings.value("customIps").toStringList(); } + void setCustomIps(const QStringList &customIps) { m_settings.setValue("customIps", customIps); } + + protected: - QSettings* m_settings; + QSettings m_settings; QString m_userName; QString m_password; QString m_serverName; diff --git a/client/ui/mainwindow.cpp b/client/ui/mainwindow.cpp index c5c00f24..ad6a6be7 100644 --- a/client/ui/mainwindow.cpp +++ b/client/ui/mainwindow.cpp @@ -1,5 +1,8 @@ #include +#include #include +#include +#include #include #include #include @@ -17,7 +20,6 @@ #include "debug.h" #include "defines.h" #include "mainwindow.h" -#include "settings.h" #include "ui_mainwindow.h" #include "utils.h" #include "vpnconnection.h" @@ -33,8 +35,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), #endif ui(new Ui::MainWindow), - m_vpnConnection(nullptr), - m_settings(new Settings) + m_vpnConnection(nullptr) { ui->setupUi(this); ui->label_error_text->clear(); @@ -43,8 +44,6 @@ MainWindow::MainWindow(QWidget *parent) : ui->stackedWidget_main->setSpeed(200); ui->stackedWidget_main->setAnimation(QEasingCurve::Linear); - ui->pushButton_blocked_list->setEnabled(false); - ui->pushButton_share_connection->setEnabled(false); #ifdef Q_OS_MAC ui->widget_tittlebar->hide(); ui->stackedWidget_main->move(0,0); @@ -53,7 +52,7 @@ MainWindow::MainWindow(QWidget *parent) : // Post initialization - if (m_settings->haveAuthData()) { + if (m_settings.haveAuthData()) { goToPage(Page::Vpn, true, false); } else { goToPage(Page::Start, true, false); @@ -62,12 +61,20 @@ MainWindow::MainWindow(QWidget *parent) : setupTray(); setupUiConnections(); + customSitesModel = new QStringListModel(); + ui->listView_sites_custom->setModel(customSitesModel); + + connect(ui->listView_sites_custom, &QListView::doubleClicked, [&](const QModelIndex &index){ + QDesktopServices::openUrl("https://" + index.data().toString()); + }); + connect(ui->lineEdit_sites_add_custom, &QLineEdit::returnPressed, [&](){ + ui->pushButton_sites_add_custom->click(); + }); + + initCustomSites(); + ui->pushButton_general_settings_exit->hide(); - ui->pushButton_share_connection->hide(); - ui->radioButton_mode_all_sites->hide(); - ui->radioButton_mode_include_selected_sites->hide(); - ui->pushButton_blocked_list->hide(); - ui->label_description->hide(); + //ui->pushButton_share_connection->hide(); setFixedSize(width(),height()); @@ -119,9 +126,9 @@ void MainWindow::goToPage(Page page, bool reset, bool slide) ui->label_server_settings_wait_info->hide(); ui->label_server_settings_wait_info->clear(); ui->label_server_settings_server->setText(QString("%1@%2:%3") - .arg(m_settings->userName()) - .arg(m_settings->serverName()) - .arg(m_settings->serverPort())); + .arg(m_settings.userName()) + .arg(m_settings.serverName()) + .arg(m_settings.serverPort())); } } @@ -241,8 +248,8 @@ void MainWindow::onPushButtonNewServerConnectWithNewData(bool) ui->label_new_server_wait_info); if (ok) { - m_settings->setServerCredentials(serverCredentials); - m_settings->save(); + m_settings.setServerCredentials(serverCredentials); + m_settings.save(); goToPage(Page::Vpn); qApp->processEvents(); @@ -251,6 +258,29 @@ void MainWindow::onPushButtonNewServerConnectWithNewData(bool) } } +void MainWindow::onPushButtonNewServerConnectWithExistingCode(bool) +{ + QString s = ui->lineEdit_start_existing_code->text(); + s.replace("vpn://", ""); + QJsonObject o = QJsonDocument::fromJson(QByteArray::fromBase64(s.toUtf8())).object(); + + qDebug().noquote() << QByteArray::fromBase64(s.toUtf8()); + ServerCredentials credentials; + credentials.hostName = o.value("h").toString(); + credentials.port = o.value("p").toInt(); + credentials.userName = o.value("u").toString(); + credentials.password = o.value("w").toString(); + + m_settings.setServerCredentials(credentials); + m_settings.save(); + + goToPage(Page::Vpn); + qDebug() << QString("Added server %3@%1:%2"). + arg(credentials.hostName). + arg(credentials.port). + arg(credentials.userName); +} + bool MainWindow::installServer(ServerCredentials credentials, QWidget *page, QProgressBar *progress, QPushButton *button, QLabel *info) { @@ -312,7 +342,7 @@ bool MainWindow::installServer(ServerCredentials credentials, void MainWindow::onPushButtonReinstallServer(bool) { onDisconnect(); - installServer(m_settings->serverCredentials(), + installServer(m_settings.serverCredentials(), ui->page_server_settings, ui->progressBar_server_settings_reinstall, ui->pushButton_server_settings_reinstall, @@ -323,7 +353,7 @@ void MainWindow::onPushButtonClearServer(bool) { onDisconnect(); - ErrorCode e = ServerController::removeServer(m_settings->serverCredentials(), Protocol::Any); + ErrorCode e = ServerController::removeServer(m_settings.serverCredentials(), Protocol::Any); if (e) { QMessageBox::warning(this, APPLICATION_NAME, tr("Error occurred while configuring server.") + "\n" + @@ -342,12 +372,12 @@ void MainWindow::onPushButtonForgetServer(bool) { onDisconnect(); - m_settings->setUserName(""); - m_settings->setPassword(""); - m_settings->setServerName(""); - m_settings->setServerPort(); + m_settings.setUserName(""); + m_settings.setPassword(""); + m_settings.setServerName(""); + m_settings.setServerPort(); - m_settings->save(); + m_settings.save(); goToPage(Page::Start); } @@ -483,6 +513,7 @@ void MainWindow::setupUiConnections() connect(ui->pushButton_connect, SIGNAL(clicked(bool)), this, SLOT(onPushButtonConnectClicked(bool))); connect(ui->pushButton_new_server_setup, &QPushButton::clicked, this, [this](){ goToPage(Page::NewServer); }); connect(ui->pushButton_new_server_connect_with_new_data, SIGNAL(clicked(bool)), this, SLOT(onPushButtonNewServerConnectWithNewData(bool))); + connect(ui->pushButton_new_server_connect, SIGNAL(clicked(bool)), this, SLOT(onPushButtonNewServerConnectWithExistingCode(bool))); connect(ui->pushButton_server_settings_reinstall, SIGNAL(clicked(bool)), this, SLOT(onPushButtonReinstallServer(bool))); connect(ui->pushButton_server_settings_clear, SIGNAL(clicked(bool)), this, SLOT(onPushButtonClearServer(bool))); @@ -491,7 +522,19 @@ void MainWindow::setupUiConnections() connect(ui->pushButton_blocked_list, &QPushButton::clicked, this, [this](){ goToPage(Page::Sites); }); connect(ui->pushButton_settings, &QPushButton::clicked, this, [this](){ goToPage(Page::GeneralSettings); }); connect(ui->pushButton_server_settings, &QPushButton::clicked, this, [this](){ goToPage(Page::ServerSettings); }); - connect(ui->pushButton_share_connection, &QPushButton::clicked, this, [this](){ goToPage(Page::ShareConnection); }); + connect(ui->pushButton_share_connection, &QPushButton::clicked, this, [this](){ + goToPage(Page::ShareConnection); + updateShareCode(); + }); + + connect(ui->pushButton_copy_sharing_code, &QPushButton::clicked, this, [this](){ + QGuiApplication::clipboard()->setText(ui->textEdit_sharing_code->toPlainText()); + ui->pushButton_copy_sharing_code->setText(tr("Copied")); + + QTimer::singleShot(3000, [this]() { + ui->pushButton_copy_sharing_code->setText(tr("Copy")); + }); + }); connect(ui->pushButton_back_from_sites, &QPushButton::clicked, this, [this](){ goToPage(Page::Vpn); }); @@ -500,6 +543,8 @@ void MainWindow::setupUiConnections() connect(ui->pushButton_back_from_server_settings, &QPushButton::clicked, this, [this](){ goToPage(Page::GeneralSettings); }); connect(ui->pushButton_back_from_share, &QPushButton::clicked, this, [this](){ goToPage(Page::GeneralSettings); }); + connect(ui->pushButton_sites_add_custom, &QPushButton::clicked, this, [this](){ onPushButtonAddCustomSitesClicked(); }); + connect(ui->pushButton_sites_delete_custom, &QPushButton::clicked, this, [this](){ onPushButtonDeleteCustomSiteClicked(); }); } void MainWindow::setTrayState(VpnProtocol::ConnectionState state) @@ -564,7 +609,7 @@ void MainWindow::onConnect() qApp->processEvents(); // TODO: Call connectToVpn with restricted server account - ServerCredentials credentials = m_settings->serverCredentials(); + ServerCredentials credentials = m_settings.serverCredentials(); ErrorCode errorCode = m_vpnConnection->connectToVpn(credentials); if (errorCode) { @@ -591,3 +636,89 @@ void MainWindow::onTrayActionConnect() } } + +void MainWindow::onPushButtonAddCustomSitesClicked() +{ + QString newSite = ui->lineEdit_sites_add_custom->text(); + + if (newSite.isEmpty()) return; + if (!newSite.contains(".")) return; + + // get domain name if it present + newSite.replace("https://", ""); + newSite.replace("http://", ""); + newSite.replace("ftp://", ""); + + newSite = newSite.split("/", QString::SkipEmptyParts).first(); + + + QStringList customSites = m_settings.customSites(); + if (!customSites.contains(newSite)) { + customSites.append(newSite); + m_settings.setCustomSites(customSites); + + QString newIp = Utils::getIPAddress(newSite); + QStringList customIps = m_settings.customIps(); + if (!newIp.isEmpty() && !customIps.contains(newIp)) { + customIps.append(newIp); + m_settings.setCustomIps(customIps); + + // add to routes immediatelly +// if (vpnStatus() == VPNStatusConnected) { +// //Router::Instance().routeAdd(newIp, vpnGate()); +// } + } + + initCustomSites(); + + ui->lineEdit_sites_add_custom->clear(); + } + else { + qDebug() << "customSites already contains" << newSite; + } +} + +void MainWindow::onPushButtonDeleteCustomSiteClicked() +{ + QModelIndex index = ui->listView_sites_custom->currentIndex(); + QString siteToDelete = index.data(Qt::DisplayRole).toString(); + + if (siteToDelete.isEmpty()) { + return; + } + + QString ipToDelete = Utils::getIPAddress(siteToDelete); + + QStringList customSites = m_settings.customSites(); + customSites.removeAll(siteToDelete); + qDebug() << "Deleted custom site:" << siteToDelete; + m_settings.setCustomSites(customSites); + + QStringList customIps = m_settings.customIps(); + customIps.removeAll(ipToDelete); + qDebug() << "Deleted custom ip:" << ipToDelete; + m_settings.setCustomIps(customIps); + + + initCustomSites(); + + //Router::Instance().routeDelete(Utils::getIPAddress(ipToDelete)); + //Router::Instance().flushDns(); +} + +void MainWindow::initCustomSites() +{ + customSitesModel->setStringList(m_settings.customSites()); +} + +void MainWindow::updateShareCode() +{ + QJsonObject o; + o.insert("h", m_settings.serverName()); + o.insert("p", m_settings.serverPort()); + o.insert("u", m_settings.userName()); + o.insert("w", m_settings.password()); + + QByteArray ba = QJsonDocument(o).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); + ui->textEdit_sharing_code->setText(QString("vpn://%1").arg(QString(ba))); +} diff --git a/client/ui/mainwindow.h b/client/ui/mainwindow.h index ef2215fb..90a4e5e0 100644 --- a/client/ui/mainwindow.h +++ b/client/ui/mainwindow.h @@ -5,12 +5,14 @@ #include #include #include +#include #include #include "framelesswindow.h" #include "protocols/vpnprotocol.h" -class Settings; +#include "settings.h" + class VpnConnection; namespace Ui { @@ -43,11 +45,15 @@ private slots: void onPushButtonConnectClicked(bool checked); void onPushButtonNewServerConnectWithNewData(bool); + void onPushButtonNewServerConnectWithExistingCode(bool); void onPushButtonReinstallServer(bool); void onPushButtonClearServer(bool); void onPushButtonForgetServer(bool); + void onPushButtonAddCustomSitesClicked(); + void onPushButtonDeleteCustomSiteClicked(); + void onTrayActionConnect(); // connect from context menu void setTrayState(VpnProtocol::ConnectionState state); @@ -68,10 +74,14 @@ private: void setTrayIcon(const QString &iconPath); void setupUiConnections(); + void initCustomSites(); + + void updateShareCode(); + Ui::MainWindow *ui; VpnConnection* m_vpnConnection; - Settings* m_settings; + Settings m_settings; QAction* m_trayActionConnect; QAction* m_trayActionDisconnect; @@ -79,6 +89,8 @@ private: QSystemTrayIcon m_tray; QMenu* m_menu; + QStringListModel *customSitesModel = nullptr; + bool canMove = false; QPoint offset; bool eventFilter(QObject *obj, QEvent *event) override; diff --git a/client/ui/mainwindow.ui b/client/ui/mainwindow.ui index adb10a6f..10ff3837 100644 --- a/client/ui/mainwindow.ui +++ b/client/ui/mainwindow.ui @@ -14,8 +14,7 @@ - /*----------------------*/ - + QLabel { color: #181922; } @@ -257,17 +256,10 @@ QPushButton:hover { - QStackedWidget#stackedWidget_main{ - background: transparent; -} - -QStackedWidget QWidget { - background: transparent; -} - + - 2 + 0 @@ -365,7 +357,7 @@ border-radius: 4px; - + 40 @@ -384,6 +376,9 @@ color: #333333; + + vpn://... + @@ -1162,17 +1157,18 @@ color: #181922; true - + - 0 - 500 - 381 - 131 + 10 + 460 + 361 + 141 - image: url(:/images/AmneziaVPN.png); + image: url(:/images/AmneziaVPN.png); +background-color: rgb(255, 255, 255); @@ -1303,7 +1299,7 @@ line-height: 25px; color: #181922; - These sites will open via VPN + These sites will be opened using VPN Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -1360,7 +1356,7 @@ border: 1px solid #A7A7A7; Qt::AlignCenter - For example, rutor.org or 17.21.111.8 + For example, yousite.com or 17.21.111.8 @@ -1379,10 +1375,10 @@ border: 1px solid #A7A7A7; PointingHandCursor - /* black */ -background: #181922; + background: #100A44; border-radius: 4px; -font-size: 18pt; +font-size: 24px; +color: white + @@ -1407,7 +1403,7 @@ font-size: 18pt; color: #181922; - Delete selected item + Delete selected site @@ -1432,7 +1428,7 @@ line-height: 150%; color: #333333; - Hostname or IP address + Web site or hostname or IP address @@ -1947,6 +1943,9 @@ color: #333333; label_server_settings_server + + + @@ -2013,17 +2012,19 @@ color: #181922; true - + 30 100 320 - 151 + 211 - background: #F5F5F5; + QTextEdit { + +background: #F5F5F5; border-radius: 10px; @@ -2036,27 +2037,32 @@ line-height: 110%; text-align: center; color: #15CDCB; + +} QTextEdit::FixedColumnWidth - 20 + 30 + + + true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Consolas'; font-size:22px; font-weight:600; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:20pt;">vpn:\\aosdiufhafafsuhgqejghuserhglaidhgauhgalgadg</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:20pt;">vpn:\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</span></p></body></html> - + 20 - 280 + 340 341 40 @@ -2090,7 +2096,7 @@ line-height: 21px; 30 - 350 + 400 321 101 diff --git a/client/utils.cpp b/client/utils.cpp index 5f23bb49..ad20df2b 100644 --- a/client/utils.cpp +++ b/client/utils.cpp @@ -111,3 +111,71 @@ bool Utils::processIsRunning(const QString& fileName) #endif } +QString Utils::getIPAddress(const QString& host) +{ + //TODO rewrite to api calls + qDebug().noquote() << "GetIPAddress: checking " + host; + if(host.isEmpty()) { + qDebug().noquote() << "GetIPAddress: host is empty."; + return QString(); + } + + if(checkIPFormat(host)) { + qDebug().noquote() << "GetIPAddress host is ip:" << host << host; + return host; // it is a ip address. + } + QProcess ping; + +#ifdef Q_OS_MACX + ping.start("ping", QStringList() << "-c1" << host); +#endif +#ifdef Q_OS_WIN + ping.start("ping", QStringList() << QString("/n") << "1" << QString("/w") << "1" << host); +#endif + ping.waitForStarted(); + + QEventLoop loop; + loop.connect(&ping, SIGNAL(finished(int)), &loop, SLOT(quit())); + loop.exec(); + + QString d = ping.readAll(); + if(d.size() == 0) + return QString(); + qDebug().noquote() << d; + + QString ip; +#ifdef Q_OS_MACX + ip = getStringBetween(d, "(", ")"); +#endif +#ifdef Q_OS_WIN + ip = getStringBetween(d, "[", "]"); +#endif + qDebug().noquote() << "GetIPAddress:" << host << ip; + return ip; +} + +QString Utils::getStringBetween(const QString& s, const QString& a, const QString& b) +{ + int ap = s.indexOf(a), bp = s.indexOf(b, ap + a.length()); + if(ap < 0 || bp < 0) + return QString(); + ap += a.length(); + if(bp - ap <= 0) + return QString(); + return s.mid(ap, bp - ap).trimmed(); +} + +bool Utils::checkIPFormat(const QString& ip) +{ + int count = ip.count("."); + if(count != 3) + return false; + + QStringList list = ip.trimmed().split("."); + foreach(QString it, list) { + if(it.toInt() <= 255 && it.toInt() >= 0) + continue; + return false; + } + return true; +} diff --git a/client/utils.h b/client/utils.h index 878cf01b..23eed83b 100644 --- a/client/utils.h +++ b/client/utils.h @@ -15,6 +15,10 @@ public: static bool createEmptyFile(const QString& path); static bool initializePath(const QString& path); static bool processIsRunning(const QString& fileName); + + static QString getIPAddress(const QString& host); + static QString getStringBetween(const QString& s, const QString& a, const QString& b); + static bool checkIPFormat(const QString& ip); }; #endif // UTILS_H diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 5da635bc..6e9c0571 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -9,6 +9,7 @@ #include "protocols/shadowsocksvpnprotocol.h" #include "utils.h" #include "vpnconnection.h" +#include "communicator.h" VpnConnection::VpnConnection(QObject* parent) : QObject(parent) { @@ -22,6 +23,25 @@ void VpnConnection::onBytesChanged(quint64 receivedBytes, quint64 sentBytes) void VpnConnection::onConnectionStateChanged(VpnProtocol::ConnectionState state) { +// if (state == VpnProtocol::ConnectionState::Connected){ +// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::FlushDnsRequest, QStringList())); + +// // add routes +// const QStringList &black_custom = m_settings.customIps(); +// qDebug() << "onConnect :: adding custom black routes, count:" << black_custom.size(); + + +// QStringList args; +// args << m_vpnProtocol->vpnGateway(); +// args << black_custom; + +// Message m(Message::State::RoutesAddRequest, args); +// m_vpnProtocol->communicator()->sendMessage(m); +// } +// else if (state == VpnProtocol::ConnectionState::Error) { +// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::ClearSavedRoutesRequest, QStringList())); +// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::FlushDnsRequest, QStringList())); +// } emit connectionStateChanged(state); } @@ -113,6 +133,9 @@ void VpnConnection::disconnectFromVpn() { qDebug() << "Disconnect from VPN"; +// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::ClearSavedRoutesRequest, QStringList())); +// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::FlushDnsRequest, QStringList())); + if (!m_vpnProtocol.data()) { return; } diff --git a/client/vpnconnection.h b/client/vpnconnection.h index 3964c40e..70f4b185 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -7,6 +7,7 @@ #include "protocols/vpnprotocol.h" #include "core/defs.h" +#include "settings.h" using namespace amnezia; @@ -41,6 +42,9 @@ protected slots: protected: QScopedPointer m_vpnProtocol; + +private: + Settings m_settings; }; #endif // VPNCONNECTION_H diff --git a/deploy/build_windows.bat b/deploy/build_windows.bat index 56c1e931..5c6db4f3 100644 --- a/deploy/build_windows.bat +++ b/deploy/build_windows.bat @@ -44,7 +44,6 @@ Rmdir /Q /S %RELEASE_DIR% Del %QMAKE_STASH_FILE% Del %TARGET_FILENAME% -# Checking env "%QT_BIN_DIR:"=%\qmake" -v nmake /? @@ -55,6 +54,7 @@ cd %WORK_DIR% set CL=/MP nmake /A /NOLOGO nmake clean +rem if not exist "%OUT_APP_DIR:"=%\%APP_FILENAME:"=%" break echo "Deploying..." "%QT_BIN_DIR:"=%\windeployqt" --release --force --no-translations "%OUT_APP_DIR:"=%\%APP_FILENAME:"=%" diff --git a/service/server/localserver.cpp b/service/server/localserver.cpp index b98a04d8..8e797065 100644 --- a/service/server/localserver.cpp +++ b/service/server/localserver.cpp @@ -6,11 +6,17 @@ #include "localserver.h" #include "utils.h" +#include "router.h" + +#ifdef Q_OS_WIN +#include "tapcontroller_win.h" +#endif + LocalServer::LocalServer(QObject *parent) : QObject(parent), m_clientConnection(nullptr), m_clientConnected(false) { - m_server = new QLocalServer(this); + m_server = QSharedPointer(new QLocalServer(this)); m_server->setSocketOptions(QLocalServer::WorldAccessOption); if (!m_server->listen(Utils::serverName())) { @@ -18,7 +24,7 @@ LocalServer::LocalServer(QObject *parent) : QObject(parent), return; } - connect(m_server, &QLocalServer::newConnection, this, &LocalServer::onNewConnection); + connect(m_server.data(), &QLocalServer::newConnection, this, &LocalServer::onNewConnection); qDebug().noquote() << QString("Local server started on '%1'").arg(m_server->serverName()); } @@ -68,9 +74,16 @@ void LocalServer::onNewConnection() qWarning().noquote() << "Message is not valid!"; continue; } + else { + qDebug().noquote() << QString("Got message id: '%1'").arg(static_cast(incomingMessage.state())); + //qDebug().noquote() << incomingMessage.rawData(); + } switch (incomingMessage.state()) { case Message::State::Initialize: + #ifdef Q_OS_WIN + TapController::Instance().checkAndSetup(); + #endif sendMessage(Message(Message::State::Initialize, QStringList({"Server"}))); break; case Message::State::StartRequest: @@ -79,6 +92,23 @@ void LocalServer::onNewConnection() case Message::State::FinishRequest: finishProcess(incomingMessage.args()); break; + + case Message::State::RoutesAddRequest: + routesAddRequest(incomingMessage.args()); + break; + case Message::State::RouteDeleteRequest: + routeDeleteRequest(incomingMessage.args()); + break; + case Message::State::ClearSavedRoutesRequest: + Router::Instance().clearSavedRoutes(); + break; + case Message::State::FlushDnsRequest: + Router::Instance().flushDns(); + break; + case Message::State::InstallDriverRequest: + checkAndInstallDriver(incomingMessage.args()); + break; + default: ; } @@ -128,6 +158,21 @@ void LocalServer::startProcess(const QStringList& messageArgs) m_processList.append(process); } +void LocalServer::routesAddRequest(const QStringList &messageArgs) +{ + Router::Instance().routeAddList(messageArgs.first(), messageArgs.mid(1)); +} + +void LocalServer::routeDeleteRequest(const QStringList &messageArgs) +{ + Router::Instance().routeDelete(messageArgs.first()); +} + +void LocalServer::checkAndInstallDriver(const QStringList &messageArgs) +{ + +} + void LocalServer::onFinished(int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitStatus) diff --git a/service/server/localserver.h b/service/server/localserver.h index d68d121e..68448004 100644 --- a/service/server/localserver.h +++ b/service/server/localserver.h @@ -2,7 +2,9 @@ #define LOCALSERVER_H #include +#include #include +#include #include #include @@ -34,8 +36,14 @@ private: void sendMessage(const Message& message); void startProcess(const QStringList& messageArgs); - QLocalServer* m_server; - QLocalSocket* m_clientConnection; + void routesAddRequest(const QStringList& messageArgs); + void routeDeleteRequest(const QStringList& messageArgs); + + void checkAndInstallDriver(const QStringList& messageArgs); + + QSharedPointer m_server; + QPointer m_clientConnection; + QVector m_processList; bool m_clientConnected; }; diff --git a/client/core/router.cpp b/service/server/router.cpp similarity index 99% rename from client/core/router.cpp rename to service/server/router.cpp index 3127549f..f642be23 100644 --- a/client/core/router.cpp +++ b/service/server/router.cpp @@ -322,6 +322,6 @@ void Router::flushDns() p.start(command); p.waitForFinished(); - qDebug().noquote() << "OUTPUT ipconfig /flushdns: " + p.readAll(); + //qDebug().noquote() << "OUTPUT ipconfig /flushdns: " + p.readAll(); #endif } diff --git a/client/core/router.h b/service/server/router.h similarity index 100% rename from client/core/router.h rename to service/server/router.h diff --git a/service/server/server.pro b/service/server/server.pro index 9ed88d9d..289b0ec4 100644 --- a/service/server/server.pro +++ b/service/server/server.pro @@ -8,6 +8,7 @@ HEADERS = \ ../../client/utils.h \ localserver.h \ log.h \ + router.h \ systemservice.h SOURCES = \ @@ -16,8 +17,26 @@ SOURCES = \ localserver.cpp \ log.cpp \ main.cpp \ + router.cpp \ systemservice.cpp +win32 { +HEADERS += \ + tapcontroller_win.h + +SOURCES += \ + tapcontroller_win.cpp + +LIBS += \ + -luser32 \ + -lrasapi32 \ + -lshlwapi \ + -liphlpapi \ + -lws2_32 \ + -liphlpapi \ + -lgdi32 +} + include(../src/qtservice.pri) #CONFIG(release, debug|release) { diff --git a/service/server/tapcontroller_win.cpp b/service/server/tapcontroller_win.cpp new file mode 100644 index 00000000..2c553fcf --- /dev/null +++ b/service/server/tapcontroller_win.cpp @@ -0,0 +1,364 @@ +#include +#include +#include +#include +#include + +#include "tapcontroller_win.h" + +#define TAP_EXE_ERROR { \ + qDebug() << "TapController: Can't start tapinstall.exe"; \ + return false; \ + } + +#define TAP_NO_MATCHING_DEVICES_ERROR { \ + qDebug() << "TapController: No matching devices found"; \ + return false; \ + } + +TapController &TapController::Instance() +{ + static TapController s; + return s; +} + +TapController::TapController() +{ +} + +bool TapController::checkInstaller() +{ + QProcess tapInstallProc; + tapInstallProc.start(getTapInstallPath(), QStringList() << "/?"); + if(!tapInstallProc.waitForStarted()) return false; + else return true; +} + +bool TapController::enableTapAdapter(const QString &tapInstanceId) +{ + QProcess tapInstallProc; + tapInstallProc.start(getTapInstallPath(), QStringList() << "enable" << QString("@") + tapInstanceId); + if(!tapInstallProc.waitForStarted()) TAP_EXE_ERROR ; + + tapInstallProc.waitForFinished(); + QString output = QString(tapInstallProc.readAll()); + if (! output.contains("are enabled")) { + qDebug() << "TapController: Failed to enable tap device"; + return false; + } + if (output.contains("No matching devices ")) TAP_NO_MATCHING_DEVICES_ERROR ; + + qDebug() << "Enabled TAP Instance id:" << tapInstanceId; + return true; +} + +bool TapController::disableTapAdapter(const QString &tapInstanceId) +{ + QProcess tapInstallProc; + tapInstallProc.start(getTapInstallPath(), QStringList() << "disable" << QString("@") + tapInstanceId); + if(!tapInstallProc.waitForStarted()) TAP_EXE_ERROR ; + + tapInstallProc.waitForFinished(); + QString output = QString(tapInstallProc.readAll()); + if (! output.contains("disabled")) { + qDebug() << "TapController: Failed to disable tap device"; + return false; + } + if (output.contains("No matching devices ")) TAP_NO_MATCHING_DEVICES_ERROR ; + + qDebug() << "Disabled TAP Instance id:" << tapInstanceId; + return true; +} + +QStringList TapController::getTapList() +{ + QProcess tapInstallProc; + tapInstallProc.start(getTapInstallPath(), QStringList() << "find" << "tap0901" ); + if(!tapInstallProc.waitForStarted()) { + qDebug() << "TapController: TapController: Can't start tapinstall.exe"; + return QStringList(); + } + tapInstallProc.waitForFinished(); + QString output = QString( tapInstallProc.readAll() ); + output.replace("\r", ""); + if (output.contains("No matched devices found")) { + qDebug() << "TapController: No matching device instances found"; + return QStringList(); + } + + QStringList l = output.split("\n", QString::SkipEmptyParts); + if (l.size() > 0) l.removeLast(); + + QStringList tapList; + for (QString s : l) { + if (s.contains(" ")) tapList.append(s.split(" ", QString::SkipEmptyParts).first()); + else tapList.append(s); + } + + return tapList; +} + +bool TapController::checkAndSetup() +{ + qDebug().noquote() << "OpenVPN path" << getOpenVpnPath(); + qDebug().noquote() << "TapInstall path" << getTapInstallPath(); + qDebug().noquote() << "TapDriverDir path" << getTapDriverDir(); + ////////////////////////////////////////////// + /// Check if OpenVPN executable ready for use + bool isOpenVpnExeExist = checkOpenVpn(); + if (!isOpenVpnExeExist) { + qDebug() << "TapController::checkAndSetup :::: openvpn.exe not found"; + return false; + } + + //////////////////////////////////////////////// + /// Check if any TAP adapter ready for use + bool isAnyAvailableTap = false; + QStringList tapList = getTapList(); + for (const QString &tap : tapList) { + qDebug() << "TapController: Found TAP device" << tap << ", checking..."; + if (checkDriver(tap)) { + isAnyAvailableTap = true; + qDebug() << "TapController: Device" << tap << "is ready for using"; + } + else + qDebug() << "TapController: Device" << tap << "is NOT ready for using"; + } + + if (isAnyAvailableTap) { + qDebug() << "TapController: Check success, found usable TAP adapter"; + return true; + } + else qDebug() << "TapController: Check failed, usable TAP adapter NOT found"; + + /// Try to setup driver if it's not installed + qDebug() << "TapController: Installing TAP driver..."; + bool ok = setupDriver(); + + if (ok) qDebug() << "TapController: TAP driver successfully installed"; + else qDebug() << "TapController: Failed to install TAP driver"; + + return ok; +} + +bool TapController::checkDriver(const QString& tapInstanceId) +{ + /// Check for driver nodes + { + QProcess tapInstallProc; + tapInstallProc.start(getTapInstallPath(), QStringList() << "drivernodes" << QString("@") + tapInstanceId); + if (!tapInstallProc.waitForStarted()) TAP_EXE_ERROR ; + tapInstallProc.waitForFinished(1000); + + QString output = QString(tapInstallProc.readAll()); + if (output.contains("No driver nodes found")) { + qDebug() << "TapController: No driver nodes found"; + return false; + } + if (output.contains("No matching devices")) TAP_NO_MATCHING_DEVICES_ERROR ; + } + + + /// Check for files + { + QProcess tapInstallProc; + tapInstallProc.start(getTapInstallPath(), QStringList() << "driverfiles" << QString("@") + tapInstanceId); + if (!tapInstallProc.waitForStarted()) TAP_EXE_ERROR ; + tapInstallProc.waitForFinished(1000); + + QString output = QString(tapInstallProc.readAll()); + if (output.contains("No driver information")) { + qDebug() << "TapController: No driver information"; + return false; + } + if (output.contains("No matching devices")) TAP_NO_MATCHING_DEVICES_ERROR ; + } + + /// Check if network adapter enabled + bool isDisabled = false; + { + QProcess tapInstallProc; + tapInstallProc.start(getTapInstallPath(), QStringList() << "status" << QString("@") + tapInstanceId); + if(!tapInstallProc.waitForStarted()) TAP_EXE_ERROR ; + + tapInstallProc.waitForFinished(); + QString output = QString(tapInstallProc.readAll()); + output.replace("\r", ""); + + if (output.contains("No matching devices ")) TAP_NO_MATCHING_DEVICES_ERROR ; + + if (output.contains("is running")) { + qDebug() << "TapController: Device" << tapInstanceId << "is active and ready"; + //return true; + } + else if (output.contains("is disabled")) isDisabled = true; + else { + qDebug() << "TapController: Device" << tapInstanceId << "is in unknown state"; + return false; + } + } + + /// Disable adapter if enabled + if (!isDisabled) { + qDebug() << "TapController: Device" << tapInstanceId << "is enabled. Disabling before use..."; + if (!disableTapAdapter(tapInstanceId)) return false; + } + + /// Enable adapter + { + qDebug() << "TapController: Device" << tapInstanceId << "is disabled. Enabling..."; + if (!enableTapAdapter(tapInstanceId)) return false; + } + + /// Check again + { + QProcess tapInstallProc; + tapInstallProc.start(getTapInstallPath(), QStringList() << "status" << QString("@") + tapInstanceId); + if(!tapInstallProc.waitForStarted()) TAP_EXE_ERROR ; + + tapInstallProc.waitForFinished(); + QString output = QString(tapInstallProc.readAll()); + + if (output.contains("is running")) return true; + else { + qDebug() << "TapController: tap device final check failed"; + return false; + } + } + +} + +bool TapController::checkOpenVpn() +{ + /// Check openvpn executable + + QProcess openVpnProc; + openVpnProc.start(getOpenVpnPath(), QStringList() << "--version"); + if (!openVpnProc.waitForStarted()) { + qDebug() << "TapController: openvpn.exe NOT found"; + return false; + } + openVpnProc.waitForFinished(1000); + + QString output = QString(openVpnProc.readAll()); + output.replace("\r", ""); + qDebug() << "TapController: openvpn.exe found, version:" << output; + return true; +} + +QString TapController::getTapInstallPath() +{ +#ifdef Q_OS_WIN + return qApp->applicationDirPath() + "\\tap\\"+ QSysInfo::currentCpuArchitecture() + "\\tapinstall.exe"; +// if (QSysInfo::currentCpuArchitecture() == "i386") { +// return qApp->applicationDirPath() + "\\openvpn\\drivers_x32\\tapinstall.exe"; +// } +// else if (QSysInfo::currentCpuArchitecture() == "x86_64") { +// return qApp->applicationDirPath() + "\\openvpn\\drivers_x64\\tapinstall.exe"; +// } +// else return ""; +#endif + return ""; +} + +QString TapController::getOpenVpnPath() +{ +#ifdef Q_OS_WIN + //return qApp->applicationDirPath() + "\\openvpn\\"+ QSysInfo::currentCpuArchitecture() + "\\openvpn.exe"; + return qApp->applicationDirPath() + "\\openvpn\\i386\\openvpn.exe"; + + //return qApp->applicationDirPath() + "\\openvpn\\bin\\openvpn.exe"; +#endif + return ""; +} + +QString TapController::getTapDriverDir() +{ + return qApp->applicationDirPath() + "\\tap\\"+ QSysInfo::currentCpuArchitecture() + "\\"; + +// if (QSysInfo::currentCpuArchitecture() == "i386") { +// return qApp->applicationDirPath() + "\\openvpn\\drivers_x32\\"; +// } +// else if (QSysInfo::currentCpuArchitecture() == "x86_64") { +// return qApp->applicationDirPath() + "\\openvpn\\drivers_x64\\"; +// } +// else return ""; +} + +bool TapController::removeDriver(const QString& tapInstanceId) +{ + /// remove tap by instance id + { + QProcess tapInstallProc; + tapInstallProc.start(getTapInstallPath(), QStringList() << "remove" << QString("@") + tapInstanceId); + if(!tapInstallProc.waitForStarted()) return false; + + tapInstallProc.waitForFinished(); + QString output = QString( tapInstallProc.readAll() ); + if (output.contains("were removed")) { + qDebug() << "TAP device" << tapInstanceId << "suceccfully removed"; + return true; + } + else { + qDebug() << "Unable to remove TAP device" << tapInstanceId; + return false; + } + } +} + +bool TapController::setupDriver() +{ + //setupDriverCertificate(); + + QStringList tapList = getTapList(); + for (QString tap : tapList) { + if (! checkDriver(tap)) removeDriver(tap); + } + tapList = getTapList(); + if (! tapList.isEmpty()) { + qDebug() << "TapController: setupDriver :::: Found drivers count" << tapList.size(); + return true; + } + + /// else try to install driver + QProcess tapInstallProc; + tapInstallProc.start(getTapInstallPath(), QStringList() << "install" << getTapDriverDir() + "OemVista.inf" << "tap0901"); + bool ok = tapInstallProc.waitForStarted(); + if (!ok) { + qDebug() << "TapController: setupDriver failer to start tapInstallProc" << tapInstallProc.errorString(); + return false; + } + + + tapInstallProc.waitForFinished(); + qDebug() << "TapController: setupDriver args" << tapInstallProc.arguments().join(" "); + qDebug() << "TapController: setupDriver output" << tapInstallProc.readAll(); + + /// check again + tapList = getTapList(); + for (QString tap : tapList) { + if (! checkDriver(tap)) removeDriver(tap); + } + tapList = getTapList(); + if (!tapList.isEmpty()) { + return true; + } + else { + return false; + } + +} + +bool TapController::setupDriverCertificate() +{ + QString cert = getTapDriverDir() + "\\OpenVPN.cer"; + QProcess tapInstallProc; + tapInstallProc.start("certutil" , QStringList() << "-addstore" << "-f" << "trustedpublisher" << cert); + + tapInstallProc.waitForFinished(); + + QString certOutput = QString(tapInstallProc.readAll()); + qDebug() << "TapController: OpenVPN certificate installed:" << certOutput; + return true; +} + diff --git a/service/server/tapcontroller_win.h b/service/server/tapcontroller_win.h new file mode 100644 index 00000000..6e1fb1ba --- /dev/null +++ b/service/server/tapcontroller_win.h @@ -0,0 +1,41 @@ +#ifndef TAPCONTROLLER_H +#define TAPCONTROLLER_H + +#include +#include +#include + +#define IPv6_DEBUG + +//! The TapController class verifies Windows Tap Controller for existance on Windows platform. + +class TapController +{ +public: + static TapController& Instance(); + static bool checkAndSetup(); + static QString getOpenVpnPath(); + + + bool checkInstaller(); + + static QStringList getTapList(); + static bool enableTapAdapter(const QString &tapInstanceId); + static bool disableTapAdapter(const QString &tapInstanceId); +private: + explicit TapController(); + TapController(TapController const &) = delete; + TapController& operator= (TapController const&) = delete; + + static bool checkDriver(const QString& tapInstanceId); + static bool checkOpenVpn(); + static QString getTapInstallPath(); + static QString getTapDriverDir(); + static bool setupDriver(); + static bool setupDriverCertificate(); + static bool removeDriver(const QString& tapInstanceId); + + +}; + +#endif // TAPCONTROLLER_H