From 6c74f30d795073a4e7c0a92f058f48bc2f5a56b2 Mon Sep 17 00:00:00 2001 From: pokamest Date: Thu, 27 May 2021 22:18:36 +0300 Subject: [PATCH] Custom sites reimplemented --- client/client.pro | 2 + client/configurators/openvpn_configurator.cpp | 2 +- client/images/folder.png | Bin 0 -> 150 bytes client/resources.qrc | 1 + client/settings.cpp | 122 ++++++ client/settings.h | 48 ++- client/ui/mainwindow.cpp | 362 ++++++++++------- client/ui/mainwindow.h | 8 +- client/ui/mainwindow.ui | 374 ++++++++++++------ client/ui/sites_model.cpp | 72 ++++ client/ui/sites_model.h | 36 ++ client/utils.cpp | 36 +- client/utils.h | 7 + client/vpnconnection.cpp | 14 +- ipc/ipcinterface.rep | 2 +- ipc/ipcserver.cpp | 4 +- ipc/ipcserver.h | 2 +- service/server/router.cpp | 6 +- service/server/router.h | 2 +- service/server/router_mac.cpp | 2 +- service/server/router_mac.h | 2 +- service/server/router_win.cpp | 39 +- service/server/router_win.h | 2 +- 23 files changed, 833 insertions(+), 312 deletions(-) create mode 100644 client/images/folder.png create mode 100644 client/ui/sites_model.cpp create mode 100644 client/ui/sites_model.h diff --git a/client/client.pro b/client/client.pro index 7ecf401b..6680ecd0 100644 --- a/client/client.pro +++ b/client/client.pro @@ -34,6 +34,7 @@ HEADERS += \ ui/mainwindow.h \ ui/qautostart.h \ ui/server_widget.h \ + ui/sites_model.h \ utils.h \ vpnconnection.h \ protocols/vpnprotocol.h \ @@ -60,6 +61,7 @@ SOURCES += \ ui/mainwindow.cpp \ ui/qautostart.cpp \ ui/server_widget.cpp \ + ui/sites_model.cpp \ utils.cpp \ vpnconnection.cpp \ protocols/vpnprotocol.cpp \ diff --git a/client/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp index 5763cee4..dcaa436c 100644 --- a/client/configurators/openvpn_configurator.cpp +++ b/client/configurators/openvpn_configurator.cpp @@ -226,7 +226,7 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString config) config.replace("$PRIMARY_DNS", m_settings().primaryDns()); config.replace("$SECONDARY_DNS", m_settings().secondaryDns()); - if (m_settings().customRouting()) { + if (m_settings().routeMode() == Settings::VpnOnlyForwardSites) { config.replace("redirect-gateway def1 bypass-dhcp", ""); } else { diff --git a/client/images/folder.png b/client/images/folder.png new file mode 100644 index 0000000000000000000000000000000000000000..07407596231dcf995b8e47972dfc075a74e1887f GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjv7RoDAs(G?Cwg-+C~&au{l7Fj z`jPnji-&Hy8Yp|2q(m^~CS@F%G(~ydgGdFZ^DXn3OHbG{&-}aEd?HimN70Q;SEqI| zu9#ylP-J>R={e($JAWNcoIkI%kTdE@^HH`dnSrNMyC-u4En@I=^>bP0l+XkK;C?oE literal 0 HcmV?d00001 diff --git a/client/resources.qrc b/client/resources.qrc index 60d3aaeb..98e4cd0b 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -61,5 +61,6 @@ server_scripts/openvpn_shadowsocks/run_container.sh server_scripts/openvpn_shadowsocks/start.sh server_scripts/openvpn_shadowsocks/template.ovpn + images/folder.png diff --git a/client/settings.cpp b/client/settings.cpp index 3c5991d1..82c9b021 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -1,5 +1,6 @@ #include "defines.h" #include "settings.h" +#include "utils.h" #include #include "protocols/protocols_defs.h" @@ -205,6 +206,127 @@ QString Settings::nextAvailableServerName() const return tr("Server") + " " + QString::number(i); } +QString Settings::routeModeString(RouteMode mode) const +{ + switch (mode) { + case VpnAllSites: + return "AllSites"; + case VpnOnlyForwardSites: + return "ForwardSites"; + case VpnAllExceptSites: + return "ExceptSites"; + } +} + +void Settings::addVpnSite(RouteMode mode, const QString &site, const QString &ip) +{ + QVariantMap sites = vpnSites(mode); + if (sites.contains(site) && ip.isEmpty()) return; + + sites.insert(site, ip); + setVpnSites(mode, sites); + +// QStringList l = sites.value(site).toStringList(); +// if (!l.contains(ip)) { +// if (!ip.isEmpty()) l.append(ip); +// //l.append(ip); +// sites.insert(site, l); +// setVpnSites(mode, sites); +// qDebug() << "sites after" << vpnSites(mode); +// } +} + +QStringList Settings::getVpnIps(RouteMode mode) const +{ + QStringList ips; + const QVariantMap &m = vpnSites(mode); + for (auto i = m.constBegin(); i != m.constEnd(); ++i) { + if (Utils::checkIPFormat(i.key())) { + ips.append(i.key()); + } + else if (Utils::checkIPFormat(i.value().toString())) { + ips.append(i.value().toString()); + } + } + ips.removeDuplicates(); + return ips; +} + +void Settings::removeVpnSite(RouteMode mode, const QString &site) +{ + QVariantMap sites = vpnSites(mode); + if (!sites.contains(site)) return; + + sites.remove(site); + setVpnSites(mode, sites); +} + +void Settings::addVpnIps(RouteMode mode, const QStringList &ips) +{ + QVariantMap sites = vpnSites(mode); + for (const QString &ip : ips) { + if (ip.isEmpty()) continue; + + sites.insert(ip, ""); + } + + setVpnSites(mode, sites); +} + +void Settings::removeVpnSites(RouteMode mode, const QStringList &sites) +{ + QVariantMap sitesMap = vpnSites(mode); + for (const QString &site : sites) { + if (site.isEmpty()) continue; + + sitesMap.remove(site); + } + + setVpnSites(mode, sitesMap); +} + +//void Settings::addVpnForwardSite(const QString &site, const QString &ip) +//{ +// auto sites = vpnForwardSites(); +// QStringList l = sites.value(site).toStringList(); +// if (!l.contains(ip)) { +// l.append(ip); +// setVpnForwardSites(sites); +// } +//} + +//QStringList Settings::getVpnForwardIps() const +//{ +// QStringList ips; +// const QVariantMap &m = vpnForwardSites(); +// for (const QVariant &v : m) { +// ips.append(v.toStringList()); +// } +// ips.removeDuplicates(); +// return ips; +//} + +//void Settings::addVpnExceptSite(const QString &site, const QString &ip) +//{ +// auto sites = vpnExceptSites(); +// QStringList l = sites.value(site).toStringList(); +// if (!l.contains(ip)) { +// l.append(ip); +// setVpnExceptSites(sites); +// } +//} + +//QStringList Settings::getVpnExceptIps() const +//{ +// QStringList ips; +// const QVariantMap &m = vpnExceptSites(); +// for (const QVariant &v : m) { +// ips.append(v.toStringList()); +// } +// ips.removeDuplicates(); +// return ips; +//} + QString Settings::primaryDns() const { return m_settings.value("Conf/primaryDns", cloudFlareNs1).toString(); } QString Settings::secondaryDns() const { return m_settings.value("Conf/secondaryDns", cloudFlareNs2).toString(); } diff --git a/client/settings.h b/client/settings.h index 97786f64..68947855 100644 --- a/client/settings.h +++ b/client/settings.h @@ -67,16 +67,48 @@ public: bool isStartMinimized() const { return m_settings.value("Conf/startMinimized", false).toBool(); } void setStartMinimized(bool enabled) { m_settings.setValue("Conf/startMinimized", enabled); } - bool customRouting() const { return m_settings.value("Conf/customRouting", false).toBool(); } - void setCustomRouting(bool customRouting) { m_settings.setValue("Conf/customRouting", customRouting); } + enum RouteMode { + VpnAllSites, + VpnOnlyForwardSites, + VpnAllExceptSites + }; + Q_ENUM (RouteMode) - // list of sites to pass blocking added by user - QStringList customSites() { return m_settings.value("Conf/customSites").toStringList(); } - void setCustomSites(const QStringList &customSites) { m_settings.setValue("Conf/customSites", customSites); } + QString routeModeString(RouteMode mode) const; - // list of ips to pass blocking generated from customSites - QStringList customIps() { return m_settings.value("Conf/customIps").toStringList(); } - void setCustomIps(const QStringList &customIps) { m_settings.setValue("Conf/customIps", customIps); } + RouteMode routeMode() const { return static_cast(m_settings.value("Conf/routeMode", 0).toInt()); } + void setRouteMode(RouteMode mode) { m_settings.setValue("Conf/routeMode", mode); } + // bool customRouting() const { return m_settings.value("Conf/customRouting", false).toBool(); } +// void setCustomRouting(bool customRouting) { m_settings.setValue("Conf/customRouting", customRouting); } + +// // list of sites to pass blocking added by user +// QStringList customSites() { return m_settings.value("Conf/customSites").toStringList(); } +// void setCustomSites(const QStringList &customSites) { m_settings.setValue("Conf/customSites", customSites); } + +// // list of ips to pass blocking generated from customSites +// QStringList customIps() { return m_settings.value("Conf/customIps").toStringList(); } +// void setCustomIps(const QStringList &customIps) { m_settings.setValue("Conf/customIps", customIps); } + + + QVariantMap vpnSites(RouteMode mode) const { return m_settings.value("Conf/" + routeModeString(mode)).toMap(); } + void setVpnSites(RouteMode mode, const QVariantMap &sites) { m_settings.setValue("Conf/"+ routeModeString(mode), sites); m_settings.sync(); } + void addVpnSite(RouteMode mode, const QString &site, const QString &ip= ""); + QStringList getVpnIps(RouteMode mode) const; + void removeVpnSite(RouteMode mode, const QString &site); + + void addVpnIps(RouteMode mode, const QStringList &ip); + void removeVpnSites(RouteMode mode, const QStringList &sites); + + +// QVariantMap vpnForwardSites() const { return m_settings.value("Conf/vpnForwardSites").toMap(); } +// void setVpnForwardSites(const QVariantMap &sites) { m_settings.setValue("Conf/vpnForwardSites", sites); } +// void addVpnForwardSite(const QString &site, const QString &ip); +// QStringList getVpnForwardIps() const; + +// QVariantMap vpnExceptSites() const { return m_settings.value("Conf/vpnExceptSites").toMap(); } +// void setVpnExceptSites(const QVariantMap &sites) { m_settings.setValue("Conf/vpnExceptSites", sites); } +// void addVpnExceptSite(const QString &site, const QString &ip); +// QStringList getVpnExceptIps() const; QString primaryDns() const; QString secondaryDns() const; diff --git a/client/ui/mainwindow.cpp b/client/ui/mainwindow.cpp index 67db1707..e10a440d 100644 --- a/client/ui/mainwindow.cpp +++ b/client/ui/mainwindow.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include #include @@ -59,6 +61,8 @@ MainWindow::MainWindow(QWidget *parent) : setupUiConnections(); setupNewServerConnections(); setupWizardConnections(); + setupVpnPageConnections(); + setupSitesPageConnections(); setupGeneralSettingsConnections(); setupAppSettingsConnections(); setupNetworkSettingsConnections(); @@ -74,6 +78,11 @@ MainWindow::MainWindow(QWidget *parent) : ui->stackedWidget_main->setSpeed(200); ui->stackedWidget_main->setAnimation(QEasingCurve::Linear); + + ui->tableView_sites->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); +// ui->tableView_sites->setColumnWidth(0, 450); +// ui->tableView_sites->setColumnWidth(1, 120); + if (QOperatingSystemVersion::current() <= QOperatingSystemVersion::Windows7) { needToHideCustomTitlebar = true; } @@ -96,10 +105,6 @@ MainWindow::MainWindow(QWidget *parent) : goToPage(Page::Vpn, true, false); } - connect(ui->lineEdit_sites_add_custom, &QLineEdit::returnPressed, [&](){ - ui->pushButton_sites_add_custom->click(); - }); - //ui->pushButton_general_settings_exit->hide(); updateSharingPage(selectedServerIndex, m_settings.serverCredentials(selectedServerIndex), selectedDockerContainer); @@ -143,6 +148,10 @@ MainWindow::MainWindow(QWidget *parent) : //ui->toolBox_share_connection->removeItem(ui->toolBox_share_connection->indexOf(ui->page_share_shadowsocks)); //ui->page_share_shadowsocks->setVisible(false); + + + sitesModels.insert(Settings::VpnOnlyForwardSites, new SitesModel(Settings::VpnOnlyForwardSites)); + sitesModels.insert(Settings::VpnAllExceptSites, new SitesModel(Settings::VpnAllExceptSites)); } MainWindow::~MainWindow() @@ -351,7 +360,8 @@ void MainWindow::keyPressEvent(QKeyEvent *event) #endif case Qt::Key_C: qDebug().noquote() << "Def server" << m_settings.defaultServerIndex() << m_settings.defaultContainerName(m_settings.defaultServerIndex()); - qDebug().noquote() << QJsonDocument(m_settings.containerConfig(m_settings.defaultServerIndex(), m_settings.defaultContainer(m_settings.defaultServerIndex()))).toJson(); + //qDebug().noquote() << QJsonDocument(m_settings.containerConfig(m_settings.defaultServerIndex(), m_settings.defaultContainer(m_settings.defaultServerIndex()))).toJson(); + qDebug().noquote() << QJsonDocument(m_settings.defaultServer()).toJson(); break; case Qt::Key_A: goToPage(Page::Start); @@ -369,6 +379,12 @@ void MainWindow::keyPressEvent(QKeyEvent *event) if (currentPage() == Page::Vpn) break; if (currentPage() == Page::ServerConfiguring) break; if (currentPage() == Page::Start && pagesStack.size() < 2) break; + if (currentPage() == Page::Sites && + ui->tableView_sites->selectionModel()->selection().indexes().size() > 0) { + ui->tableView_sites->clearSelection(); + break; + } + if (! ui->stackedWidget_main->isAnimationRunning() && ui->stackedWidget_main->currentWidget()->isEnabled()) { closePage(); } @@ -626,6 +642,17 @@ void MainWindow::onPushButtonNewServerImport(bool) credentials.password = o.value("w").toString(); if (credentials.password.isEmpty()) credentials.password = o.value(config_key::password).toString(); + if (credentials.isValid()) { + o.insert(config_key::hostName, credentials.hostName); + o.insert(config_key::port, credentials.port); + o.insert(config_key::userName, credentials.userName); + o.insert(config_key::password, credentials.password); + + o.remove("h"); + o.remove("p"); + o.remove("u"); + o.remove("w"); + } qDebug() << QString("Added server %3@%1:%2"). arg(credentials.hostName). arg(credentials.port). @@ -901,8 +928,7 @@ void MainWindow::onConnectionStateChanged(VpnProtocol::ConnectionState state) } ui->pushButton_connect->setEnabled(pushButtonConnectEnabled); - ui->radioButton_mode_all_sites->setEnabled(radioButtonsModeEnabled); - ui->radioButton_mode_selected_sites->setEnabled(radioButtonsModeEnabled); + ui->widget_vpn_mode->setEnabled(radioButtonsModeEnabled); } void MainWindow::onVpnProtocolError(ErrorCode errorCode) @@ -1013,27 +1039,6 @@ void MainWindow::setupUiConnections() connect(b, &QPushButton::clicked, this, [this](){ closePage(); }); } - connect(ui->pushButton_sites_add_custom, &QPushButton::clicked, this, [this](){ onPushButtonAddCustomSitesClicked(); }); - - connect(ui->radioButton_mode_selected_sites, &QRadioButton::toggled, ui->pushButton_vpn_add_site, &QPushButton::setEnabled); - - connect(ui->radioButton_mode_selected_sites, &QRadioButton::toggled, this, [this](bool toggled) { - m_settings.setCustomRouting(toggled); - }); - - connect(ui->pushButton_servers_add_new, &QPushButton::clicked, this, [this](){ goToPage(Page::Start); }); - - connect(ui->lineEdit_server_settings_description, &QLineEdit::editingFinished, this, [this](){ - const QString &newText = ui->lineEdit_server_settings_description->text(); - QJsonObject server = m_settings.server(selectedServerIndex); - server.insert(config_key::description, newText); - m_settings.editServer(selectedServerIndex, server); - updateServersListPage(); - }); - - connect(ui->lineEdit_server_settings_description, &QLineEdit::returnPressed, this, [this](){ - ui->lineEdit_server_settings_description->clearFocus(); - }); } void MainWindow::setupNewServerConnections() @@ -1080,7 +1085,8 @@ void MainWindow::setupWizardConnections() connect(ui->pushButton_setup_wizard_vpn_mode_finish, &QPushButton::clicked, this, [this](){ installServer(getInstallConfigsFromWizardPage()); - m_settings.setCustomRouting(ui->checkBox_setup_wizard_vpn_mode->isChecked()); + if (ui->checkBox_setup_wizard_vpn_mode->isChecked()) m_settings.setRouteMode(Settings::VpnOnlyForwardSites); + else m_settings.setRouteMode(Settings::VpnAllSites); }); connect(ui->pushButton_setup_wizard_low_finish, &QPushButton::clicked, this, [this](){ @@ -1092,6 +1098,86 @@ void MainWindow::setupWizardConnections() }); } +void MainWindow::setupVpnPageConnections() +{ + connect(ui->radioButton_vpn_mode_all_sites, &QRadioButton::toggled, ui->pushButton_vpn_add_site, &QPushButton::setDisabled); + + connect(ui->radioButton_vpn_mode_all_sites, &QRadioButton::toggled, this, [this](bool toggled) { + m_settings.setRouteMode(Settings::VpnAllSites); + }); + + connect(ui->radioButton_vpn_mode_forward_sites, &QRadioButton::toggled, this, [this](bool toggled) { + m_settings.setRouteMode(Settings::VpnOnlyForwardSites); + }); + + connect(ui->radioButton_vpn_mode_except_sites, &QRadioButton::toggled, this, [this](bool toggled) { + m_settings.setRouteMode(Settings::VpnAllExceptSites); + }); +} + +void MainWindow::setupSitesPageConnections() +{ + connect(ui->pushButton_sites_add_custom, &QPushButton::clicked, this, [this](){ onPushButtonAddCustomSitesClicked(); }); + + connect(ui->lineEdit_sites_add_custom, &QLineEdit::returnPressed, [&](){ + ui->pushButton_sites_add_custom->click(); + }); + + connect(ui->pushButton_sites_delete, &QPushButton::clicked, this, [this](){ + Settings::RouteMode mode = m_settings.routeMode(); + + QItemSelectionModel* selection = ui->tableView_sites->selectionModel(); + if (!selection) return; + + QModelIndexList indexes = selection->selectedRows(); + + QStringList sites; + for (const QModelIndex &index : indexes) { + sites.append(index.data().toString()); + } + + m_settings.removeVpnSites(mode, sites); + updateSitesPage(); + + // if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) { + // if (IpcClient::Interface()) IpcClient::Interface()->routeDelete(ipToDelete, ""); + // if (IpcClient::Interface()) IpcClient::Interface()->flushDns(); + // } + + +// if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) { +// if (IpcClient::Interface()) +// IpcClient::Interface()->routeDelete(m_vpnConnection->vpnProtocol()->vpnGateway(), +// QStringList() << ip); +// } + }); + + connect(ui->pushButton_sites_import, &QPushButton::clicked, this, [this](){ + QString fileName = QFileDialog::getOpenFileName(this, tr("Import IP addresses"), + QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); + + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) return; + + Settings::RouteMode mode = m_settings.routeMode(); + + QStringList ips; + while (!file.atEnd()) { + QString line = file.readLine(); + + int pos = 0; + QRegExp rx = Utils::ipAddressWithSubnetRegExp(); + while ((pos = rx.indexIn(line, pos)) != -1) { + ips << rx.cap(0); + pos += rx.matchedLength(); + } + } + + m_settings.addVpnIps(mode, ips); + updateSitesPage(); + }); +} + void MainWindow::setupAppSettingsConnections() { connect(ui->checkBox_app_settings_autostart, &QCheckBox::stateChanged, this, [this](int state){ @@ -1413,7 +1499,13 @@ void MainWindow::setupNewServerPageConnections() void MainWindow::setupServerSettingsPageConnections() { + connect(ui->pushButton_servers_add_new, &QPushButton::clicked, this, [this](){ goToPage(Page::Start); }); + connect(ui->pushButton_server_settings_protocols, &QPushButton::clicked, this, [this](){ goToPage(Page::ServerVpnProtocols); }); + connect(ui->pushButton_server_settings_share_full, &QPushButton::clicked, this, [this](){ + updateSharingPage(selectedServerIndex, m_settings.serverCredentials(selectedServerIndex), DockerContainer::None); + goToPage(Page::ShareConnection); + }); connect(ui->pushButton_server_settings_clear, SIGNAL(clicked(bool)), this, SLOT(onPushButtonClearServer(bool))); connect(ui->pushButton_server_settings_forget, SIGNAL(clicked(bool)), this, SLOT(onPushButtonForgetServer(bool))); @@ -1431,6 +1523,17 @@ void MainWindow::setupServerSettingsPageConnections() }); }); + connect(ui->lineEdit_server_settings_description, &QLineEdit::editingFinished, this, [this](){ + const QString &newText = ui->lineEdit_server_settings_description->text(); + QJsonObject server = m_settings.server(selectedServerIndex); + server.insert(config_key::description, newText); + m_settings.editServer(selectedServerIndex, server); + updateServersListPage(); + }); + + connect(ui->lineEdit_server_settings_description, &QLineEdit::returnPressed, this, [this](){ + ui->lineEdit_server_settings_description->clearFocus(); + }); } void MainWindow::setupSharePageConnections() @@ -1683,67 +1786,57 @@ void MainWindow::onTrayActionConnect() void MainWindow::onPushButtonAddCustomSitesClicked() { + if (ui->radioButton_vpn_mode_all_sites->isChecked()) return; + Settings::RouteMode mode = m_settings.routeMode(); + 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://", ""); + if (!Utils::ipAddressWithSubnetRegExp().exactMatch(newSite)) { + // get domain name if it present + newSite.replace("https://", ""); + newSite.replace("http://", ""); + newSite.replace("ftp://", ""); - newSite = newSite.split("/", QString::SkipEmptyParts).first(); + newSite = newSite.split("/", QString::SkipEmptyParts).first(); + } + qDebug() << "Adding site" << newSite; - QStringList customSites = m_settings.customSites(); - if (!customSites.contains(newSite)) { - customSites.append(newSite); - m_settings.setCustomSites(customSites); + //qDebug() << "sites:" << m_settings.vpnSites(mode); - QString newIp = Utils::getIPAddress(newSite); - QStringList customIps = m_settings.customIps(); - if (!newIp.isEmpty() && !customIps.contains(newIp)) { - customIps.append(newIp); - m_settings.setCustomIps(customIps); + const auto &cbProcess = [this, mode](const QString &newSite, const QString &ip) { + m_settings.addVpnSite(mode, newSite, ip); - if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) { - if (IpcClient::Interface()) IpcClient::Interface()->routeAddList(m_vpnConnection->vpnProtocol()->vpnGateway(), - QStringList() << newIp); - } + if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) { + if (IpcClient::Interface()) + IpcClient::Interface()->routeAddList(m_vpnConnection->vpnProtocol()->vpnGateway(), + QStringList() << ip); } updateSitesPage(); - ui->lineEdit_sites_add_custom->clear(); - } - else { - qDebug() << "customSites already contains" << newSite; - } -} + }; -void MainWindow::onPushButtonDeleteCustomSiteClicked(const QString &siteToDelete) -{ - if (siteToDelete.isEmpty()) { + const auto &cbResolv = [this, cbProcess](const QHostInfo &hostInfo){ + const QList &addresses = hostInfo.addresses(); + if (!addresses.isEmpty()) { + //qDebug() << "Resolved address for" << hostInfo.hostName() << addresses.first().toString(); + cbProcess(hostInfo.hostName(), addresses.first().toString()); + } + }; + + ui->lineEdit_sites_add_custom->clear(); + + if (Utils::ipAddressWithSubnetRegExp().exactMatch(newSite)) { + cbProcess(newSite, newSite); 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); - - updateSitesPage(); - - if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) { - if (IpcClient::Interface()) IpcClient::Interface()->routeDelete(ipToDelete, ""); - if (IpcClient::Interface()) IpcClient::Interface()->flushDns(); + else { + cbProcess(newSite, ""); + updateSitesPage(); + int reqId = QHostInfo::lookupHost(newSite, this, cbResolv); } } @@ -1769,16 +1862,20 @@ void MainWindow::updateStartPage() void MainWindow::updateSitesPage() { - ui->listWidget_sites->clear(); - for (const QString &site : m_settings.customSites()) { - makeSitesListItem(ui->listWidget_sites, site); - } + Settings::RouteMode m = m_settings.routeMode(); + if (m == Settings::VpnAllSites) return; + + ui->tableView_sites->setModel(sitesModels.value(m)); + sitesModels.value(m)->resetCache(); } void MainWindow::updateVpnPage() { - ui->radioButton_mode_selected_sites->setChecked(m_settings.customRouting()); - ui->pushButton_vpn_add_site->setEnabled(m_settings.customRouting()); + Settings::RouteMode mode = m_settings.routeMode(); + ui->radioButton_vpn_mode_all_sites->setChecked(mode == Settings::VpnAllSites); + ui->radioButton_vpn_mode_forward_sites->setChecked(mode == Settings::VpnOnlyForwardSites); + ui->radioButton_vpn_mode_except_sites->setChecked(mode == Settings::VpnAllExceptSites); + ui->pushButton_vpn_add_site->setEnabled(mode != Settings::VpnAllSites); } void MainWindow::updateAppSettingsPage() @@ -1868,20 +1965,6 @@ void MainWindow::updateProtocolsPage() ui->frame_openvpn_settings->setVisible(containers.contains(DockerContainer::OpenVpn)); } -void MainWindow::updateShareCodePage() -{ -// 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))); - - //qDebug() << "Share code" << QJsonDocument(o).toJson(); -} - void MainWindow::updateOpenVpnPage(const QJsonObject &openvpnConfig, DockerContainer container, bool haveAuthData) { ui->widget_proto_openvpn->setEnabled(haveAuthData); @@ -1968,34 +2051,43 @@ void MainWindow::updateSharingPage(int serverIndex, const ServerCredentials &cre const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container); - for (QWidget *page : { ui->page_share_openvpn, - ui->page_share_shadowsocks, - ui->page_share_cloak, - ui->page_share_full_access }) { + for (QWidget *page : { + ui->page_share_amnezia, + ui->page_share_openvpn, + ui->page_share_shadowsocks, + ui->page_share_cloak, + ui->page_share_full_access }) { ui->toolBox_share_connection->removeItem(ui->toolBox_share_connection->indexOf(page)); page->hide(); } if (container == DockerContainer::OpenVpn) { + ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client")); ui->toolBox_share_connection->addItem(ui->page_share_openvpn, tr(" Share for OpenVPN client")); - QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::OpenVpn); - QString cfg = protoConfig.value(config_key::last_config).toString(); - if (!cfg.isEmpty()) { - // TODO add redirect-gateway def1 bypass-dhcp here and on click Generate config - ui->textEdit_share_openvpn_code->setPlainText(cfg); - } - else { - cfg = tr("Press Generate config"); - ui->textEdit_share_openvpn_code->setPlainText(cfg); - ui->pushButton_share_openvpn_copy->setEnabled(false); - ui->pushButton_share_openvpn_save->setEnabled(false); - } + QString cfg = tr("Press Generate config"); + ui->textEdit_share_openvpn_code->setPlainText(cfg); + ui->pushButton_share_openvpn_copy->setEnabled(false); + ui->pushButton_share_openvpn_save->setEnabled(false); + +// QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::OpenVpn); +// QString cfg = protoConfig.value(config_key::last_config).toString(); +// if (!cfg.isEmpty()) { +// // TODO add redirect-gateway def1 bypass-dhcp here and on click Generate config +// ui->textEdit_share_openvpn_code->setPlainText(cfg); +// } +// else { +// cfg = tr("Press Generate config"); +// ui->textEdit_share_openvpn_code->setPlainText(cfg); +// ui->pushButton_share_openvpn_copy->setEnabled(false); +// ui->pushButton_share_openvpn_save->setEnabled(false); +// } ui->toolBox_share_connection->setCurrentWidget(ui->page_share_openvpn); } if (container == DockerContainer::OpenVpnOverShadowSocks) { + ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client")); ui->toolBox_share_connection->addItem(ui->page_share_shadowsocks, tr(" Share for ShadowSocks client")); QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::ShadowSocks); @@ -2034,6 +2126,24 @@ void MainWindow::updateSharingPage(int serverIndex, const ServerCredentials &cre ui->toolBox_share_connection->layout()->update(); } + if (container == DockerContainer::OpenVpnOverCloak) { + ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client")); + } + + // Full access + if (container == DockerContainer::None) { + ui->toolBox_share_connection->addItem(ui->page_share_full_access, tr(" Share server full access")); + + const QJsonObject &server = m_settings.server(selectedServerIndex); + + QByteArray ba = QJsonDocument(server).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); + + ui->textEdit_share_full_code->setText(QString("vpn://%1").arg(QString(ba))); + ui->toolBox_share_connection->setCurrentWidget(ui->page_share_full_access); + } + + //ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client")); + // Amnezia sharing // QJsonObject exportContainer; // for (Protocol p: protocolsForContainer(container)) { @@ -2046,38 +2156,6 @@ void MainWindow::updateSharingPage(int serverIndex, const ServerCredentials &cre // ui->textEdit_share_amnezia_code->setPlainText(QJsonDocument(exportContainer).toJson()); ui->textEdit_share_amnezia_code->setPlainText(tr("")); - repaint(); - update(); - updateGeometry(); -} - -void MainWindow::makeSitesListItem(QListWidget *listWidget, const QString &address) -{ - QSize size(310, 25); - QWidget* widget = new QWidget; - widget->resize(size); - - QLabel *label = new QLabel(address, widget); - label->resize(size); - - QPushButton* btn = new QPushButton(widget); - btn->resize(size); - - QPushButton* btn1 = new QPushButton(widget); - btn1->resize(30, 25); - btn1->move(280, 0); - btn1->setCursor(QCursor(Qt::PointingHandCursor)); - - connect(btn1, &QPushButton::clicked, this, [this, label]() { - onPushButtonDeleteCustomSiteClicked(label->text()); - return; - }); - - QListWidgetItem* item = new QListWidgetItem(listWidget); - item->setSizeHint(size); - listWidget->setItemWidget(item, widget); - - widget->setStyleSheet(styleSheet()); } void MainWindow::makeServersListItem(QListWidget *listWidget, const QJsonObject &server, bool isDefault, int index) diff --git a/client/ui/mainwindow.h b/client/ui/mainwindow.h index c79f609e..32fa99f4 100644 --- a/client/ui/mainwindow.h +++ b/client/ui/mainwindow.h @@ -17,6 +17,7 @@ #include "protocols/vpnprotocol.h" #include "settings.h" +#include "sites_model.h" class VpnConnection; @@ -63,7 +64,6 @@ private slots: void onPushButtonForgetServer(bool); void onPushButtonAddCustomSitesClicked(); - void onPushButtonDeleteCustomSiteClicked(const QString &siteToDelete); void onTrayActionConnect(); // connect from context menu void setTrayState(VpnProtocol::ConnectionState state); @@ -94,6 +94,8 @@ private: void setupUiConnections(); void setupNewServerConnections(); void setupWizardConnections(); + void setupVpnPageConnections(); + void setupSitesPageConnections(); void setupAppSettingsConnections(); void setupGeneralSettingsConnections(); void setupNetworkSettingsConnections(); @@ -110,7 +112,6 @@ private: void updateServerPage(); void updateServersListPage(); void updateProtocolsPage(); - void updateShareCodePage(); void updateOpenVpnPage(const QJsonObject &openvpnConfig, DockerContainer container, bool haveAuthData); void updateShadowSocksPage(const QJsonObject &ssConfig, DockerContainer container, bool haveAuthData); void updateCloakPage(const QJsonObject &ckConfig, DockerContainer container, bool haveAuthData); @@ -118,7 +119,6 @@ private: void updateSharingPage(int serverIndex, const ServerCredentials &credentials, DockerContainer container); - void makeSitesListItem(QListWidget* listWidget, const QString &address); void makeServersListItem(QListWidget* listWidget, const QJsonObject &server, bool isDefault, int index); void updateQRCodeImage(const QString &text, QLabel *label); @@ -135,6 +135,8 @@ private: VpnConnection* m_vpnConnection; Settings m_settings; + QMap sitesModels; + QAction* m_trayActionConnect; QAction* m_trayActionDisconnect; diff --git a/client/ui/mainwindow.ui b/client/ui/mainwindow.ui index a77f17d2..cbfb20b4 100644 --- a/client/ui/mainwindow.ui +++ b/client/ui/mainwindow.ui @@ -11,7 +11,7 @@ - + AmneziaVPN QMainWindow { @@ -120,18 +120,18 @@ border-image: url(:/images/controls/check_on.png); } - QScrollBar:vertical { /* The area behind the scrollbar covering entire height. */ - background-color: grey; + background-color: rgba(0, 0, 0,0); opacity: 100; - width: 7px; /* set width to zero to hide scrollbar entirely. Can look quite clean and scrolling still works with mousewheel. */ - margin: 0px 0px; /* Takes the height of the buttons + 3 extra pixels to leave some free space between handle and buttons */ + width: 10px; /* set width to zero to hide scrollbar entirely. Can look quite clean and scrolling still works with mousewheel. */ + margin: 10px px; /* Takes the height of the buttons + 3 extra pixels to leave some free space between handle and buttons */ } QScrollBar::handle:vertical { /* The handle you scroll with */ image-position: center; /* image is used as a small gripper in the center of the scrollbar.. You can also use background-image to use two images */ background-color: rgb(200, 200, 200); + border: 2px solid rgb(240,240,240); border-radius: 1px; min-height: 10px; } @@ -143,7 +143,7 @@ QScrollBar::handle:vertical:pressed { /* state when you hover over the handle */ } QScrollBar::sub-line:vertical { /* button to scroll up */ background-color: rgb(240,240,240); - height: 0px; + height: 10px; subcontrol-position: top; subcontrol-origin: margin; } @@ -158,7 +158,8 @@ QScrollBar::up-arrow:vertical { /* arrow to scroll up with */ QScrollBar::add-line:vertical { /* Button to scroll down */ background-color: rgb(240,240,240); - height: 0px; + height: 10px; + padding-top: 2px; subcontrol-position: bottom; subcontrol-origin: margin; } @@ -171,27 +172,9 @@ QScrollBar::down-arrow:vertical { /* arrow to scroll down with */ } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { - background-color: black; -} + background-color: rgb(240,240,240); -/* -QGroupBox { - border: 1px solid lightgray; - border-radius: 2px; - margin-top: 1ex; -} - -QGroupBox::title { - font-size: 16px; - font-style: normal; - font-weight: normal; - color: #181922; - - subcontrol-origin: margin; - subcontrol-position: top left; - padding: 0 3px; -} -*/ +} @@ -291,7 +274,7 @@ QPushButton:hover { - 1 + 10 @@ -2720,7 +2703,7 @@ background: #211966; 0 - 370 + 360 380 51 @@ -2826,7 +2809,7 @@ font: 16px "Lato"; 20 - 550 + 560 341 40 @@ -2960,9 +2943,9 @@ color: #181922; 20 - 450 + 440 281 - 31 + 21 @@ -2983,49 +2966,11 @@ color: #181922; Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - - 20 - 490 - 341 - 19 - - - - For all connections - - - true - - - - - true - - - - 20 - 520 - 341 - 19 - - - - For selected sites - - - false - - 0 - 290 + 280 381 61 @@ -3043,10 +2988,77 @@ color: #181922; true + + + + 20 + 470 + 351 + 91 + + + + + true + + + + 0 + 60 + 341 + 19 + + + + Except selected sites + + + false + + + + + true + + + + 0 + 30 + 341 + 19 + + + + For selected sites + + + false + + + + + true + + + + 0 + 0 + 341 + 19 + + + + For all connections + + + true + + + - QListView { + /*QListView { outline: 0; background: transparent; border: none; @@ -3071,7 +3083,8 @@ QListView::item:selected { border: none; background: rgba(167, 167, 167, 0.1); color: #181922; -} +} +*/ @@ -3160,7 +3173,7 @@ color: #100A44; 20 140 - 281 + 231 31 @@ -3191,7 +3204,7 @@ color: #100A44; Qt::AlignCenter - For example, yousite.com or 17.21.111.8 + yousite.com or IP address @@ -3200,7 +3213,7 @@ color: #100A44; - 310 + 260 140 51 31 @@ -3246,50 +3259,127 @@ line-height: 150%; color: #333333; - Web site or hostname or IP address + Web site/Hostname/IP address/Subnet - + 20 200 - 340 - 400 + 341 + 371 - QWidget { - margin: 0px; - padding: 0px; -} - -QPushButton:hover { - image: url(:/images/close.png); - image-position: right center; -} - -QListView { - show-decoration-selected: 1; /* make the selection span the entire width of the view */ -} - -QListView::item:selected:!active { + QTableView { background: transparent; + gridline-color: transparent; + border: none; + outline: none; + show-decoration-selected: 1; } -QListView::item:selected:active { - background: transparent; - border: none; +QTableView::item +{ + padding-left: 5px; + border-top: 1px solid lightgray; + color: #181922; } -QListView::item:hover { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0 #FAFBFE, stop: 1 #ECEEFF); +QTableView::item::selected +{ + border: 0px; + padding-left: 5px; + background-color: rgb(99, 180, 251); + border: : rgb(99, 180, 251); } - QAbstractItemView::NoSelection + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + false + + + Qt::NoPen + + + false + + + false + + + false + + + + + + 80 + 589 + 231 + 31 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Delete selected + + + + + true + + + + 320 + 140 + 51 + 31 + + + + PointingHandCursor + + + QPushButton { +background: #100A44; +border-radius: 4px; +padding: 5px; +image: url(:/images/folder.png); +} +QPushButton:hover { +background: #211966; +} + + + @@ -4471,7 +4561,7 @@ font-weight: bold; 40 - 220 + 210 300 40 @@ -4528,6 +4618,40 @@ font-size: 20px; Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + 40 + 260 + 300 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Share Server (FULL ACCESS) + + label_server_settings_wait_info label_16 label_17 @@ -4539,6 +4663,7 @@ font-size: 20px; pushButton_server_settings_protocols pushButton_back_from_server_settings label_server_settings_current_vpn_protocol + pushButton_server_settings_share_full @@ -5284,7 +5409,30 @@ border-radius: 4px 0px 0px 4px; - + QScrollBar::sub-line:vertical { /* button to scroll up */ + border-top-right-radius: 3px; + background-color: rgb(240,240,240); + height: 10px; + subcontrol-position: top; + subcontrol-origin: margin; + margin-top: 3px; +} + + +QScrollBar::add-line:vertical { /* Button to scroll down */ + border-bottom-right-radius: 3px; + background-color: rgb(240,240,240); + height: 10px; + padding-top: 2px; + subcontrol-position: bottom; + subcontrol-origin: margin; + margin-bottom: 3px; +} + + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background-color: rgb(240,240,240); +} @@ -5391,7 +5539,7 @@ QToolBox::tab:hover { 0 - 1 + 0 6 @@ -5401,8 +5549,8 @@ QToolBox::tab:hover { 0 0 - 100 - 30 + 360 + 360 @@ -5725,8 +5873,8 @@ background: #282932; 0 0 - 100 - 30 + 360 + 360 @@ -5891,8 +6039,8 @@ background: #282932; 0 0 - 100 - 30 + 360 + 360 @@ -6115,8 +6263,8 @@ color: #15CDCB; 0 0 - 100 - 30 + 360 + 360 diff --git a/client/ui/sites_model.cpp b/client/ui/sites_model.cpp new file mode 100644 index 00000000..8cddf734 --- /dev/null +++ b/client/ui/sites_model.cpp @@ -0,0 +1,72 @@ +#include "sites_model.h" + +SitesModel::SitesModel(Settings::RouteMode mode, QObject *parent) + : m_mode(mode), + QAbstractTableModel(parent) +{ +} + +void SitesModel::resetCache() +{ + beginResetModel(); + m_ipsCache.clear(); + m_cacheReady = false; + endResetModel(); +} + +QVariant SitesModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + // FIXME: Implement me! + return QVariant(); +} + +int SitesModel::rowCount(const QModelIndex &parent) const +{ + if (!m_cacheReady) genCache(); + return m_ipsCache.size(); +} + +int SitesModel::columnCount(const QModelIndex &parent) const +{ + return 2; +} + +QVariant SitesModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (!m_cacheReady) genCache(); + + if (role == Qt::DisplayRole){ + if (m_ipsCache.isEmpty()) return QVariant(); + + if (index.column() == 0) { + return m_ipsCache.at(index.row()).first; + } + if (index.column() == 1) { + return m_ipsCache.at(index.row()).second; + } + } + +// if (role == Qt::TextAlignmentRole && index.column() == 1) { +// return Qt::AlignRight; +// } + + return QVariant(); +} + +void SitesModel::genCache() const +{ + qDebug() << "SitesModel::genCache"; + m_ipsCache.clear(); + + const QVariantMap &sites = m_settings.vpnSites(m_mode); + auto i = sites.constBegin(); + while (i != sites.constEnd()) { + m_ipsCache.append(qMakePair(i.key(), i.value().toString())); + ++i; + } + + m_cacheReady= true; +} diff --git a/client/ui/sites_model.h b/client/ui/sites_model.h new file mode 100644 index 00000000..b6921fe4 --- /dev/null +++ b/client/ui/sites_model.h @@ -0,0 +1,36 @@ +#ifndef SITESMODEL_H +#define SITESMODEL_H + +#include + +#include "settings.h" + +class SitesModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit SitesModel(Settings::RouteMode mode, QObject *parent = nullptr); + void resetCache(); + + // Header: + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + + // Basic functionality: + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + +private: + void genCache() const; + +private: + Settings::RouteMode m_mode; + Settings m_settings; + + mutable QVector> m_ipsCache; + mutable bool m_cacheReady = false; +}; + +#endif // SITESMODEL_H diff --git a/client/utils.cpp b/client/utils.cpp index 99079ff9..6c8983d2 100644 --- a/client/utils.cpp +++ b/client/utils.cpp @@ -146,7 +146,7 @@ bool Utils::checkIPFormat(const QString& ip) return false; QStringList list = ip.trimmed().split("."); - foreach(QString it, list) { + for (const QString &it : list) { if(it.toInt() <= 255 && it.toInt() >= 0) continue; return false; @@ -154,6 +154,18 @@ bool Utils::checkIPFormat(const QString& ip) return true; } +bool Utils::checkIpSubnetFormat(const QString &ip) +{ + if (!ip.contains("/")) return checkIPFormat(ip); + + QStringList parts = ip.split("/"); + if (parts.size() != 2) return false; + + bool ok; + if (parts.at(1).toInt(&ok) <= 32 && ok) return checkIPFormat(parts.at(0)); + else return false; +} + void Utils::killProcessByName(const QString &name) { qDebug().noquote() << "Kill process" << name; @@ -164,6 +176,28 @@ void Utils::killProcessByName(const QString &name) #endif } +QString Utils::netMaskFromIpWithSubnet(const QString ip) +{ + if (!ip.contains("/")) return "255.255.255.255"; + + bool ok; + int prefix = ip.split("/").at(1).toInt(&ok); + if (!ok) return "255.255.255.255"; + + unsigned long mask = (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF; + + return QString("%1.%2.%3.%4") + .arg(mask >> 24) + .arg((mask >> 16) & 0xFF) + .arg((mask >> 8) & 0xFF) + .arg( mask & 0xFF); +} + +QString Utils::ipAddressFromIpWithSubnet(const QString ip) +{ + return ip.split("/").first(); +} + #ifdef Q_OS_WIN // Inspired from http://stackoverflow.com/a/15281070/1529139 // and http://stackoverflow.com/q/40059902/1529139 diff --git a/client/utils.h b/client/utils.h index b4b4b425..29ab6544 100644 --- a/client/utils.h +++ b/client/utils.h @@ -23,10 +23,14 @@ public: static QString getIPAddress(const QString& host); static QString getStringBetween(const QString& s, const QString& a, const QString& b); static bool checkIPFormat(const QString& ip); + static bool checkIpSubnetFormat(const QString& ip); static QRegExp ipAddressRegExp() { return QRegExp("^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\\.(?!$)|$)){4}$"); } static QRegExp ipAddressPortRegExp() { return QRegExp("^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}" "(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(\\:[0-9]{1,5}){0,1}$"); } + static QRegExp ipAddressWithSubnetRegExp() { return QRegExp("(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}" + "(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(\\/[0-9]{1,2}){0,1}"); } + static QRegExp ipNetwork24RegExp() { return QRegExp("^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}" "0$"); } @@ -35,6 +39,9 @@ public: static bool processIsRunning(const QString& fileName); static void killProcessByName(const QString &name); + static QString netMaskFromIpWithSubnet(const QString ip); + static QString ipAddressFromIpWithSubnet(const QString ip); + #ifdef Q_OS_WIN static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent); #endif diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index f40a94f6..6e4f54b8 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -43,22 +43,22 @@ void VpnConnection::onConnectionStateChanged(VpnProtocol::ConnectionState state) if (state == VpnProtocol::ConnectionState::Connected && IpcClient::Interface()){ IpcClient::Interface()->flushDns(); - if (m_settings.customRouting()) { + if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) { IpcClient::Interface()->routeDelete("0.0.0.0", m_vpnProtocol->vpnGateway()); IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << m_settings.primaryDns() << m_settings.secondaryDns()); - const QStringList &black_custom = m_settings.customIps(); - qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << black_custom.size(); + const QStringList &forwardIps = m_settings.getVpnIps(Settings::VpnOnlyForwardSites); + qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << forwardIps.size(); - IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), black_custom); + IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), forwardIps); } } else if (state == VpnProtocol::ConnectionState::Error) { IpcClient::Interface()->flushDns(); - if (m_settings.customRouting()) { + if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) { IpcClient::Interface()->clearSavedRoutes(); } } @@ -199,7 +199,7 @@ ErrorCode VpnConnection::createVpnConfiguration(int serverIndex, ErrorCode VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig) { - qDebug() << "СonnectToVpn, CustomRouting is" << m_settings.customRouting(); + qDebug() << "СonnectToVpn, Route mode is" << m_settings.routeMode(); emit connectionStateChanged(VpnProtocol::ConnectionState::Connecting); @@ -276,7 +276,7 @@ void VpnConnection::disconnectFromVpn() if (IpcClient::Interface()) { IpcClient::Interface()->flushDns(); - if (m_settings.customRouting()) { + if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) { IpcClient::Interface()->clearSavedRoutes(); } } diff --git a/ipc/ipcinterface.rep b/ipc/ipcinterface.rep index 80293961..b2e6020a 100644 --- a/ipc/ipcinterface.rep +++ b/ipc/ipcinterface.rep @@ -7,7 +7,7 @@ class IpcInterface //SIGNAL(sendMessage(const QByteArray &message)); // Route functions - SLOT( bool routeAdd(const QString &ip, const QString &gw, const QString &mask) ); + SLOT( bool routeAdd(const QString &ip, const QString &gw) ); SLOT( int routeAddList(const QString &gw, const QStringList &ips) ); SLOT( bool clearSavedRoutes() ); SLOT( bool routeDelete(const QString &ip, const QString &gw) ); diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index 4ba546a7..2423c21c 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -53,9 +53,9 @@ int IpcServer::createPrivilegedProcess() return m_localpid; } -bool IpcServer::routeAdd(const QString &ip, const QString &gw, const QString &mask) +bool IpcServer::routeAdd(const QString &ip, const QString &gw) { - return Router::routeAdd(ip, gw, mask); + return Router::routeAdd(ip, gw); } int IpcServer::routeAddList(const QString &gw, const QStringList &ips) diff --git a/ipc/ipcserver.h b/ipc/ipcserver.h index 9978bde3..b981d1ce 100644 --- a/ipc/ipcserver.h +++ b/ipc/ipcserver.h @@ -15,7 +15,7 @@ public: explicit IpcServer(QObject *parent = nullptr); virtual int createPrivilegedProcess() override; - virtual bool routeAdd(const QString &ip, const QString &gw, const QString &mask = QString()) override; + virtual bool routeAdd(const QString &ip, const QString &gw) override; virtual int routeAddList(const QString &gw, const QStringList &ips) override; virtual bool clearSavedRoutes() override; virtual bool routeDelete(const QString &ip, const QString &gw) override; diff --git a/service/server/router.cpp b/service/server/router.cpp index c5497153..e9ec7f92 100644 --- a/service/server/router.cpp +++ b/service/server/router.cpp @@ -7,12 +7,12 @@ #endif -bool Router::routeAdd(const QString &ip, const QString &gw, QString mask) +bool Router::routeAdd(const QString &ip, const QString &gw) { #ifdef Q_OS_WIN - return RouterWin::Instance().routeAdd(ip, gw, mask); + return RouterWin::Instance().routeAdd(ip, gw); #elif defined (Q_OS_MAC) - return RouterMac::Instance().routeAdd(ip, gw, mask); + return RouterMac::Instance().routeAdd(ip, gw); #endif } diff --git a/service/server/router.h b/service/server/router.h index 5ad49be2..e79db486 100644 --- a/service/server/router.h +++ b/service/server/router.h @@ -15,7 +15,7 @@ class Router : public QObject { Q_OBJECT public: - static bool routeAdd(const QString &ip, const QString &gw, QString mask = QString()); + static bool routeAdd(const QString &ip, const QString &gw); static int routeAddList(const QString &gw, const QStringList &ips); static bool clearSavedRoutes(); static bool routeDelete(const QString &ip, const QString &gw); diff --git a/service/server/router_mac.cpp b/service/server/router_mac.cpp index f413e712..7c39bbf7 100644 --- a/service/server/router_mac.cpp +++ b/service/server/router_mac.cpp @@ -9,7 +9,7 @@ RouterMac &RouterMac::Instance() return s; } -bool RouterMac::routeAdd(const QString &ip, const QString &gw, QString mask) +bool RouterMac::routeAdd(const QString &ip, const QString &gw) { int argc = 5; char **argv = new char*[argc]; diff --git a/service/server/router_mac.h b/service/server/router_mac.h index 53a0f35e..4b03d108 100644 --- a/service/server/router_mac.h +++ b/service/server/router_mac.h @@ -18,7 +18,7 @@ class RouterMac : public QObject public: static RouterMac& Instance(); - bool routeAdd(const QString &ip, const QString &gw, QString mask = QString()); + bool routeAdd(const QString &ip, const QString &gw); int routeAddList(const QString &gw, const QStringList &ips); bool clearSavedRoutes(); bool routeDelete(const QString &ip, const QString &gw); diff --git a/service/server/router_win.cpp b/service/server/router_win.cpp index e09ffd25..95759f13 100644 --- a/service/server/router_win.cpp +++ b/service/server/router_win.cpp @@ -1,4 +1,5 @@ #include "router_win.h" +#include "../client/utils.h" #include @@ -8,20 +9,11 @@ RouterWin &RouterWin::Instance() return s; } -bool RouterWin::routeAdd(const QString &ip, const QString &gw, QString mask) +bool RouterWin::routeAdd(const QString &ip, const QString &gw) { - qDebug().noquote() << QString("ROUTE ADD: IP:%1 %2 GW %3") - .arg(ip) - .arg(mask) - .arg(gw); - - if (mask == "") { - mask = "255.255.255.255"; - if (ip.endsWith(".0")) mask = "255.255.255.0"; - if (ip.endsWith(".0.0")) mask = "255.255.0.0"; - if (ip.endsWith(".0.0.0")) mask = "255.0.0.0"; - } + //qDebug().noquote() << QString("ROUTE ADD: IP:%1 GW %2").arg(ip).arg(gw); + QString mask = Utils::netMaskFromIpWithSubnet(ip); PMIB_IPFORWARDTABLE pIpForwardTable = NULL; MIB_IPFORWARDROW ipfrow; @@ -58,7 +50,7 @@ bool RouterWin::routeAdd(const QString &ip, const QString &gw, QString mask) } // address - ipfrow.dwForwardDest = inet_addr(ip.toStdString().c_str()); + ipfrow.dwForwardDest = inet_addr(Utils::ipAddressFromIpWithSubnet(ip).toStdString().c_str()); // mask in_addr maskAddr; @@ -109,12 +101,12 @@ bool RouterWin::routeAdd(const QString &ip, const QString &gw, QString mask) int RouterWin::routeAddList(const QString &gw, const QStringList &ips) { - qDebug().noquote() << QString("ROUTE ADD List: IPs size:%1, GW: %2") - .arg(ips.size()) - .arg(gw); +// qDebug().noquote() << QString("ROUTE ADD List: IPs size:%1, GW: %2") +// .arg(ips.size()) +// .arg(gw); - qDebug().noquote() << QString("ROUTE ADD List: IPs:\n%1") - .arg(ips.join("\n")); +// qDebug().noquote() << QString("ROUTE ADD List: IPs:\n%1") +// .arg(ips.join("\n")); @@ -188,15 +180,10 @@ int RouterWin::routeAddList(const QString &gw, const QStringList &ips) for (int i = 0; i < ips.size(); ++i) { QString ip = ips.at(i); if (ip.isEmpty()) continue; - - mask = "255.255.255.255"; - if (ip.endsWith(".0")) mask = "255.255.255.0"; - if (ip.endsWith(".0.0")) mask = "255.255.0.0"; - if (ip.endsWith(".0.0.0")) mask = "255.0.0.0"; + QString mask = Utils::netMaskFromIpWithSubnet(ip); // address - ipfrow.dwForwardDest = inet_addr(ip.toStdString().c_str()); - + ipfrow.dwForwardDest = inet_addr(Utils::ipAddressFromIpWithSubnet(ip).toStdString().c_str()); // mask in_addr maskAddr; @@ -280,7 +267,7 @@ bool RouterWin::routeDelete(const QString &ip, const QString &gw) QProcess p; p.setProcessChannelMode(QProcess::MergedChannels); - QString command = QString("route delete %1 %2").arg(ip).arg(gw); + QString command = QString("route delete %1 %2").arg(Utils::ipAddressFromIpWithSubnet(ip)).arg(gw); p.start(command); p.waitForFinished(); diff --git a/service/server/router_win.h b/service/server/router_win.h index e9de7be1..98222e2b 100644 --- a/service/server/router_win.h +++ b/service/server/router_win.h @@ -38,7 +38,7 @@ class RouterWin : public QObject public: static RouterWin& Instance(); - bool routeAdd(const QString &ip, const QString &gw, QString mask = QString()); + bool routeAdd(const QString &ip, const QString &gw); int routeAddList(const QString &gw, const QStringList &ips); bool clearSavedRoutes(); bool routeDelete(const QString &ip, const QString &gw);