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 00000000..07407596
Binary files /dev/null and b/client/images/folder.png differ
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);