Bug fixes:

- auto install tap
- share connectionState
- service crash fix
This commit is contained in:
pokamest 2021-01-26 15:01:15 +03:00
parent a50cdd5bc2
commit 953eca6695
25 changed files with 919 additions and 89 deletions

View file

@ -14,14 +14,13 @@ HEADERS += \
core/defs.h \
core/errorstrings.h \
core/openvpnconfigurator.h \
core/router.h \
core/servercontroller.h \
debug.h \
defines.h \
localclient.h \
managementserver.h \
message.h \
protocols/shadowsocksvpnprotocol.h \
protocols/shadowsocksvpnprotocol.h \
runguard.h \
settings.h \
ui/Controls/SlidingStackedWidget.h \
@ -34,14 +33,13 @@ HEADERS += \
SOURCES += \
communicator.cpp \
core/openvpnconfigurator.cpp \
core/router.cpp \
core/servercontroller.cpp \
debug.cpp \
localclient.cpp \
main.cpp \
managementserver.cpp \
message.cpp \
protocols/shadowsocksvpnprotocol.cpp \
protocols/shadowsocksvpnprotocol.cpp \
runguard.cpp \
settings.cpp \
ui/Controls/SlidingStackedWidget.cpp \

View file

@ -72,5 +72,8 @@ void Communicator::sendMessage(const Message& message)
const QString data = message.toString();
bool status = writeData(data + "\n");
qDebug().noquote() << QString("Send message '%1', status '%2'").arg(data).arg(Utils::toString(status));
qDebug().noquote() << QString("Send message '%1',%2 status '%2'").
arg(static_cast<int>(message.state())).
arg(data).
arg(Utils::toString(status));
}

View file

@ -1,327 +0,0 @@
#include "router.h"
#include <QProcess>
Router &Router::Instance()
{
static Router s;
return s;
}
bool Router::routeAdd(const QString &ip, const QString &gw, QString mask)
{
qDebug().noquote() << QString("ROUTE ADD: IP:%1 %2 GW %3")
.arg(ip)
.arg(mask)
.arg(gw);
#ifdef Q_OS_WIN
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";
}
PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
MIB_IPFORWARDROW ipfrow;
DWORD dwSize = 0;
BOOL bOrder = FALSE;
DWORD dwStatus = 0;
// Find out how big our buffer needs to be.
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
if (dwStatus == ERROR_INSUFFICIENT_BUFFER) {
// Allocate the memory for the table
if (!(pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc(dwSize))) {
qDebug() << "Malloc failed. Out of memory.";
return false;
}
// Now get the table.
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
}
if (dwStatus != ERROR_SUCCESS) {
qDebug() << "getIpForwardTable failed.";
if (pIpForwardTable)
free(pIpForwardTable);
return false;
}
// Set iface for route
IPAddr dwGwAddr = inet_addr(gw.toStdString().c_str());
if (GetBestInterface(dwGwAddr, &ipfrow.dwForwardIfIndex) != NO_ERROR) {
qDebug() << "Router::routeAdd : GetBestInterface failed";
return false;
}
// address
ipfrow.dwForwardDest = inet_addr(ip.toStdString().c_str());
// mask
in_addr maskAddr;
inet_pton(AF_INET, mask.toStdString().c_str(), &maskAddr);
ipfrow.dwForwardMask = maskAddr.S_un.S_addr;
// Get TAP iface metric to set it for new routes
MIB_IPINTERFACE_ROW tap_iface;
InitializeIpInterfaceEntry(&tap_iface);
tap_iface.InterfaceIndex = ipfrow.dwForwardIfIndex;
tap_iface.Family = AF_INET;
dwStatus = GetIpInterfaceEntry(&tap_iface);
if (dwStatus == NO_ERROR){
ipfrow.dwForwardMetric1 = tap_iface.Metric;
}
else {
qDebug() << "Router::routeAdd: failed GetIpInterfaceEntry(), Error:" << dwStatus;
ipfrow.dwForwardMetric1 = 256;
}
ipfrow.dwForwardMetric2 = 0;
ipfrow.dwForwardMetric3 = 0;
ipfrow.dwForwardMetric4 = 0;
ipfrow.dwForwardMetric5 = 0;
ipfrow.dwForwardAge = 0;
ipfrow.dwForwardNextHop = inet_addr(gw.toStdString().c_str());
ipfrow.dwForwardType = 4; /* XXX - next hop != final dest */
ipfrow.dwForwardProto = 3; /* XXX - MIB_PROTO_NETMGMT */
dwStatus = CreateIpForwardEntry(&ipfrow);
if (dwStatus == NO_ERROR){
ipForwardRows.append(ipfrow);
//qDebug() << "Gateway changed successfully";
}
else {
qDebug() << "Router::routeAdd: failed CreateIpForwardEntry()";
qDebug() << "Error: " << dwStatus;
}
// Free resources
if (pIpForwardTable)
free(pIpForwardTable);
return (dwStatus == NO_ERROR);
#else
// Not implemented yet
return false;
#endif
}
int Router::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:\n%1")
.arg(ips.join("\n"));
#ifdef Q_OS_WIN
PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
DWORD dwSize = 0;
BOOL bOrder = FALSE;
DWORD dwStatus = 0;
// Find out how big our buffer needs to be.
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
if (dwStatus == ERROR_INSUFFICIENT_BUFFER) {
// Allocate the memory for the table
if (!(pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc(dwSize))) {
qDebug() << "Malloc failed. Out of memory.";
return 0;
}
// Now get the table.
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
}
if (dwStatus != ERROR_SUCCESS) {
qDebug() << "getIpForwardTable failed.";
if (pIpForwardTable)
free(pIpForwardTable);
return 0;
}
int success_count = 0;
QString mask;
MIB_IPFORWARDROW ipfrow;
ipfrow.dwForwardPolicy = 0;
ipfrow.dwForwardAge = 0;
ipfrow.dwForwardNextHop = inet_addr(gw.toStdString().c_str());
ipfrow.dwForwardType = 4; /* XXX - next hop != final dest */
ipfrow.dwForwardProto = 3; /* XXX - MIB_PROTO_NETMGMT */
// Set iface for route
IPAddr dwGwAddr = inet_addr(gw.toStdString().c_str());
if (GetBestInterface(dwGwAddr, &ipfrow.dwForwardIfIndex) != NO_ERROR) {
qDebug() << "Router::routeAddList : GetBestInterface failed";
return false;
}
// Get TAP iface metric to set it for new routes
MIB_IPINTERFACE_ROW tap_iface;
InitializeIpInterfaceEntry(&tap_iface);
tap_iface.InterfaceIndex = ipfrow.dwForwardIfIndex;
tap_iface.Family = AF_INET;
dwStatus = GetIpInterfaceEntry(&tap_iface);
if (dwStatus == NO_ERROR){
ipfrow.dwForwardMetric1 = tap_iface.Metric;
}
else {
qDebug() << "Router::routeAddList: failed GetIpInterfaceEntry(), Error:" << dwStatus;
ipfrow.dwForwardMetric1 = 256;
}
ipfrow.dwForwardMetric2 = 0;
ipfrow.dwForwardMetric3 = 0;
ipfrow.dwForwardMetric4 = 0;
ipfrow.dwForwardMetric5 = 0;
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";
// address
ipfrow.dwForwardDest = inet_addr(ip.toStdString().c_str());
// mask
in_addr maskAddr;
inet_pton(AF_INET, mask.toStdString().c_str(), &maskAddr);
ipfrow.dwForwardMask = maskAddr.S_un.S_addr;
dwStatus = CreateIpForwardEntry(&ipfrow);
if (dwStatus == NO_ERROR){
ipForwardRows.append(ipfrow);
//qDebug() << "Gateway changed successfully";
}
else {
qDebug() << "Router::routeAdd: failed CreateIpForwardEntry(), Error:" << ip << dwStatus;
}
if (dwStatus == NO_ERROR) success_count++;
}
// Free resources
if (pIpForwardTable)
free(pIpForwardTable);
qDebug() << "Router::routeAddList finished, success: " << success_count << "/" << ips.size();
return success_count;
#else
// Not implemented yet
return false;
#endif
}
bool Router::clearSavedRoutes()
{
#ifdef Q_OS_WIN
if (ipForwardRows.isEmpty()) return true;
qDebug() << "forward rows size:" << ipForwardRows.size();
// Declare and initialize variables
PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
DWORD dwSize = 0;
BOOL bOrder = FALSE;
DWORD dwStatus = 0;
// Find out how big our buffer needs to be.
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
if (dwStatus == ERROR_INSUFFICIENT_BUFFER) {
// Allocate the memory for the table
if (!(pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc(dwSize))) {
qDebug() << "Router::clearSavedRoutes : Malloc failed. Out of memory";
return false;
}
// Now get the table.
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
}
if (dwStatus != ERROR_SUCCESS) {
qDebug() << "Router::clearSavedRoutes : getIpForwardTable failed";
if (pIpForwardTable)
free(pIpForwardTable);
return false;
}
int removed_count = 0;
for (int i = 0; i < ipForwardRows.size(); ++i) {
dwStatus = DeleteIpForwardEntry(&ipForwardRows[i]);
if (dwStatus != ERROR_SUCCESS) {
qDebug() << "Router::clearSavedRoutes : Could not delete old row" << i;
}
else removed_count++;
}
if (pIpForwardTable)
free(pIpForwardTable);
qDebug() << "Router::clearSavedRoutes : removed routes:" << removed_count << "of" << ipForwardRows.size();
ipForwardRows.clear();
return true;
#else
// Not implemented yet
return false;
#endif
}
bool Router::routeDelete(const QString &ip)
{
qDebug().noquote() << QString("ROUTE DELETE, IP: %1").arg(ip);
#ifdef Q_OS_WIN
QProcess p;
p.setProcessChannelMode(QProcess::MergedChannels);
QString command = QString("route delete %1")
.arg(ip);
p.start(command);
p.waitForFinished();
qDebug().noquote() << "OUTPUT route delete: " + p.readAll();
return true;
#else
// Not implemented yet
return false;
#endif
}
void Router::flushDns()
{
#ifdef Q_OS_WIN
QProcess p;
p.setProcessChannelMode(QProcess::MergedChannels);
QString command = QString("ipconfig /flushdns");
p.start(command);
p.waitForFinished();
qDebug().noquote() << "OUTPUT ipconfig /flushdns: " + p.readAll();
#endif
}

View file

@ -1,60 +0,0 @@
#ifndef ROUTER_H
#define ROUTER_H
#include <QTimer>
#include <QString>
#include <QSettings>
#include <QHash>
#include <QDebug>
#ifdef Q_OS_WIN
#include <WinSock2.h> //includes Windows.h
#include <WS2tcpip.h>
#include <iphlpapi.h>
#include <IcmpAPI.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t u8_t ;
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#endif //Q_OS_WIN
/**
* @brief The Router class - General class for handling ip routing
*/
class Router : public QObject
{
Q_OBJECT
public:
static Router& Instance();
bool routeAdd(const QString &ip, const QString &gw, QString mask = QString());
int routeAddList(const QString &gw, const QStringList &ips);
bool clearSavedRoutes();
bool routeDelete(const QString &ip);
void flushDns();
public slots:
private:
Router() {}
Router(Router const &) = delete;
Router& operator= (Router const&) = delete;
#ifdef Q_OS_WIN
QList<MIB_IPFORWARDROW> ipForwardRows;
#endif
};
#endif // ROUTER_H

View file

@ -22,12 +22,22 @@ QString Message::textState() const
case State::Started: return "Started";
case State::FinishRequest: return "FinishRequest";
case State::Finished: return "Finished";
case State::RoutesAddRequest: return "RoutesAddRequest";
case State::RouteDeleteRequest: return "RouteDeleteRequest";
case State::ClearSavedRoutesRequest: return "ClearSavedRoutesRequest";
case State::FlushDnsRequest: return "FlushDnsRequest";
case State::InstallDriverRequest: return "InstallDriverRequest";
default:
;
}
return QString();
}
QString Message::rawData() const
{
return m_rawData;
}
Message::State Message::state() const
{
return m_state;
@ -66,6 +76,7 @@ QString Message::argsToString() const
Message::Message(const QString& data)
{
m_rawData = data;
m_valid = false;
if (data.isEmpty()) {
return;
@ -77,7 +88,7 @@ Message::Message(const QString& data)
}
bool stateFound = false;
for (int i = static_cast<int>(State::Unknown); i <= static_cast<int>(State::Finished); i++ ) {
for (int i = static_cast<int>(State::Unknown); i <= static_cast<int>(State::InstallDriverRequest); i++ ) {
m_state = static_cast<State>(i);
if (textState() == dataList.at(0)) {
stateFound = true;

View file

@ -6,7 +6,8 @@
class Message {
public:
enum class State {Unknown, Initialize, StartRequest, Started, FinishRequest, Finished};
enum class State {Unknown, Initialize, StartRequest, Started, FinishRequest, Finished,
RoutesAddRequest, RouteDeleteRequest, ClearSavedRoutesRequest, FlushDnsRequest, InstallDriverRequest};
Message(State state, const QStringList& args);
Message(const QString& data);
@ -16,6 +17,7 @@ public:
QStringList args() const;
State state() const;
bool isValid() const;
QString rawData() const;
protected:
QString textState() const;
@ -26,6 +28,7 @@ protected:
bool m_valid;
State m_state;
QStringList m_args;
QString m_rawData;
};
#endif // MESSAGE_H

View file

@ -1,5 +1,7 @@
#include <QCoreApplication>
#include <QFileInfo>
#include <QProcess>
#include <QRegularExpression>
#include <QTcpSocket>
#include "communicator.h"
@ -106,6 +108,15 @@ void OpenVpnProtocol::writeCommand(const QString& command)
}
}
void OpenVpnProtocol::updateRouteGateway(QString line)
{
line = line.split("ROUTE_GATEWAY", QString::SkipEmptyParts).at(1);
if (!line.contains("/")) return;
m_routeGateway = line.split("/", QString::SkipEmptyParts).first();
m_routeGateway.replace(" ", "");
qDebug() << "Set VPN route gateway" << m_routeGateway;
}
QString OpenVpnProtocol::openVpnExecPath() const
{
#ifdef Q_OS_WIN
@ -209,6 +220,7 @@ void OpenVpnProtocol::onReadyReadDataFromManagementServer()
if (line.contains("CONNECTED,SUCCESS")) {
sendByteCount();
stopTimeoutTimer();
updateVpnGateway();
setConnectionState(VpnProtocol::ConnectionState::Connected);
continue;
} else if (line.contains("EXITING,SIGTER")) {
@ -220,6 +232,10 @@ void OpenVpnProtocol::onReadyReadDataFromManagementServer()
}
}
if (line.contains("ROUTE_GATEWAY")) {
updateRouteGateway(line);
}
if (line.contains("FATAL")) {
if (line.contains("tap-windows6 adapters on this system are currently in use or disabled")) {
emit protocolError(ErrorCode::OpenVpnAdaptersInUseError);
@ -259,4 +275,46 @@ void OpenVpnProtocol::onOpenVpnProcessFinished(int exitCode)
setConnectionState(VpnProtocol::ConnectionState::Disconnected);
}
void OpenVpnProtocol::updateVpnGateway()
{
QProcess ipconfig;
ipconfig.start("ipconfig", QStringList() << "/all");
ipconfig.waitForStarted();
ipconfig.waitForFinished();
QString d = ipconfig.readAll();
d.replace("\r", "");
//qDebug().noquote() << d;
QStringList adapters = d.split(":\n");
bool isTapV9Present = false;
QString tapV9;
for (int i = 0; i < adapters.size(); ++i) {
if (adapters.at(i).contains("TAP-Windows Adapter V9")) {
isTapV9Present = true;
tapV9 = adapters.at(i);
break;
}
}
if (!isTapV9Present) {
m_vpnGateway = "";
}
QStringList lines = tapV9.split("\n");
for (int i = 0; i < lines.size(); ++i) {
if (!lines.at(i).contains("DHCP")) continue;
QRegularExpression re("(: )([\\d\\.]+)($)");
QRegularExpressionMatch match = re.match(lines.at(i));
if (match.hasMatch()) {
qDebug().noquote() << "Current VPN Gateway IP Address: " << match.captured(0);
m_vpnGateway = match.captured(2);
return;
}
else continue;
}
m_vpnGateway = "";
}

View file

@ -46,6 +46,11 @@ protected:
QString m_configFileName;
QTimer m_openVpnStateSigTermHandlerTimer;
bool m_requestFromUserToStop;
private:
void updateRouteGateway(QString line);
void updateVpnGateway();
};
#endif // OPENVPNPROTOCOL_H

View file

@ -94,6 +94,16 @@ void VpnProtocol::setConnectionState(VpnProtocol::ConnectionState state)
emit connectionStateChanged(m_connectionState);
}
QString VpnProtocol::vpnGateway() const
{
return m_vpnGateway;
}
QString VpnProtocol::routeGateway() const
{
return m_routeGateway;
}
QString VpnProtocol::textConnectionState(ConnectionState connectionState)
{
switch (connectionState) {

View file

@ -35,6 +35,9 @@ public:
QString textConnectionState() const;
void setLastError(ErrorCode lastError);
QString routeGateway() const;
QString vpnGateway() const;
signals:
void bytesChanged(quint64 receivedBytes, quint64 sentBytes);
void connectionStateChanged(VpnProtocol::ConnectionState state);
@ -54,12 +57,15 @@ protected:
static Communicator* m_communicator;
ConnectionState m_connectionState;
QString m_routeGateway;
QString m_vpnGateway;
private:
QTimer* m_timeoutTimer;
ErrorCode m_lastError;
quint64 m_receivedBytes;
quint64 m_sentBytes;
};
#endif // VPNPROTOCOL_H

View file

@ -1,32 +1,32 @@
#include <QSettings>
#include "defines.h"
#include "settings.h"
Settings::Settings(QObject* parent) : QObject(parent)
Settings::Settings(QObject* parent) :
QObject(parent),
m_settings (ORGANIZATION_NAME, APPLICATION_NAME, this)
{
m_settings = new QSettings(ORGANIZATION_NAME, APPLICATION_NAME, this);
read();
}
void Settings::read()
{
m_settings->beginGroup("Server");
m_userName = m_settings->value("userName", QString()).toString();
m_password = m_settings->value("password", QString()).toString();
m_serverName = m_settings->value("serverName", QString()).toString();
m_serverPort = m_settings->value("serverPort", 22).toInt();
m_settings->endGroup();
m_settings.beginGroup("Server");
m_userName = m_settings.value("userName", QString()).toString();
m_password = m_settings.value("password", QString()).toString();
m_serverName = m_settings.value("serverName", QString()).toString();
m_serverPort = m_settings.value("serverPort", 22).toInt();
m_settings.endGroup();
}
void Settings::save()
{
m_settings->beginGroup("Server");
m_settings->setValue("userName", m_userName);
m_settings->setValue("password", m_password);
m_settings->setValue("serverName", m_serverName);
m_settings->setValue("serverPort", m_serverPort);
m_settings->endGroup();
m_settings.beginGroup("Server");
m_settings.setValue("userName", m_userName);
m_settings.setValue("password", m_password);
m_settings.setValue("serverName", m_serverName);
m_settings.setValue("serverPort", m_serverPort);
m_settings.endGroup();
}
bool Settings::haveAuthData() const

View file

@ -3,6 +3,7 @@
#include <QObject>
#include <QString>
#include <QSettings>
#include "core/defs.h"
@ -35,8 +36,18 @@ public:
bool haveAuthData() const;
// list of sites to pass blocking added by user
QStringList customSites() { return m_settings.value("customSites").toStringList(); }
void setCustomSites(const QStringList &customSites) { m_settings.setValue("customSites", customSites); }
// list of ips to pass blocking generated from customSites
QStringList customIps() { return m_settings.value("customIps").toStringList(); }
void setCustomIps(const QStringList &customIps) { m_settings.setValue("customIps", customIps); }
protected:
QSettings* m_settings;
QSettings m_settings;
QString m_userName;
QString m_password;
QString m_serverName;

View file

@ -1,5 +1,8 @@
#include <QApplication>
#include <QClipboard>
#include <QDesktopServices>
#include <QJsonDocument>
#include <QJsonObject>
#include <QKeyEvent>
#include <QMenu>
#include <QMessageBox>
@ -17,7 +20,6 @@
#include "debug.h"
#include "defines.h"
#include "mainwindow.h"
#include "settings.h"
#include "ui_mainwindow.h"
#include "utils.h"
#include "vpnconnection.h"
@ -33,8 +35,7 @@ MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
#endif
ui(new Ui::MainWindow),
m_vpnConnection(nullptr),
m_settings(new Settings)
m_vpnConnection(nullptr)
{
ui->setupUi(this);
ui->label_error_text->clear();
@ -43,8 +44,6 @@ MainWindow::MainWindow(QWidget *parent) :
ui->stackedWidget_main->setSpeed(200);
ui->stackedWidget_main->setAnimation(QEasingCurve::Linear);
ui->pushButton_blocked_list->setEnabled(false);
ui->pushButton_share_connection->setEnabled(false);
#ifdef Q_OS_MAC
ui->widget_tittlebar->hide();
ui->stackedWidget_main->move(0,0);
@ -53,7 +52,7 @@ MainWindow::MainWindow(QWidget *parent) :
// Post initialization
if (m_settings->haveAuthData()) {
if (m_settings.haveAuthData()) {
goToPage(Page::Vpn, true, false);
} else {
goToPage(Page::Start, true, false);
@ -62,12 +61,20 @@ MainWindow::MainWindow(QWidget *parent) :
setupTray();
setupUiConnections();
customSitesModel = new QStringListModel();
ui->listView_sites_custom->setModel(customSitesModel);
connect(ui->listView_sites_custom, &QListView::doubleClicked, [&](const QModelIndex &index){
QDesktopServices::openUrl("https://" + index.data().toString());
});
connect(ui->lineEdit_sites_add_custom, &QLineEdit::returnPressed, [&](){
ui->pushButton_sites_add_custom->click();
});
initCustomSites();
ui->pushButton_general_settings_exit->hide();
ui->pushButton_share_connection->hide();
ui->radioButton_mode_all_sites->hide();
ui->radioButton_mode_include_selected_sites->hide();
ui->pushButton_blocked_list->hide();
ui->label_description->hide();
//ui->pushButton_share_connection->hide();
setFixedSize(width(),height());
@ -119,9 +126,9 @@ void MainWindow::goToPage(Page page, bool reset, bool slide)
ui->label_server_settings_wait_info->hide();
ui->label_server_settings_wait_info->clear();
ui->label_server_settings_server->setText(QString("%1@%2:%3")
.arg(m_settings->userName())
.arg(m_settings->serverName())
.arg(m_settings->serverPort()));
.arg(m_settings.userName())
.arg(m_settings.serverName())
.arg(m_settings.serverPort()));
}
}
@ -241,8 +248,8 @@ void MainWindow::onPushButtonNewServerConnectWithNewData(bool)
ui->label_new_server_wait_info);
if (ok) {
m_settings->setServerCredentials(serverCredentials);
m_settings->save();
m_settings.setServerCredentials(serverCredentials);
m_settings.save();
goToPage(Page::Vpn);
qApp->processEvents();
@ -251,6 +258,29 @@ void MainWindow::onPushButtonNewServerConnectWithNewData(bool)
}
}
void MainWindow::onPushButtonNewServerConnectWithExistingCode(bool)
{
QString s = ui->lineEdit_start_existing_code->text();
s.replace("vpn://", "");
QJsonObject o = QJsonDocument::fromJson(QByteArray::fromBase64(s.toUtf8())).object();
qDebug().noquote() << QByteArray::fromBase64(s.toUtf8());
ServerCredentials credentials;
credentials.hostName = o.value("h").toString();
credentials.port = o.value("p").toInt();
credentials.userName = o.value("u").toString();
credentials.password = o.value("w").toString();
m_settings.setServerCredentials(credentials);
m_settings.save();
goToPage(Page::Vpn);
qDebug() << QString("Added server %3@%1:%2").
arg(credentials.hostName).
arg(credentials.port).
arg(credentials.userName);
}
bool MainWindow::installServer(ServerCredentials credentials,
QWidget *page, QProgressBar *progress, QPushButton *button, QLabel *info)
{
@ -312,7 +342,7 @@ bool MainWindow::installServer(ServerCredentials credentials,
void MainWindow::onPushButtonReinstallServer(bool)
{
onDisconnect();
installServer(m_settings->serverCredentials(),
installServer(m_settings.serverCredentials(),
ui->page_server_settings,
ui->progressBar_server_settings_reinstall,
ui->pushButton_server_settings_reinstall,
@ -323,7 +353,7 @@ void MainWindow::onPushButtonClearServer(bool)
{
onDisconnect();
ErrorCode e = ServerController::removeServer(m_settings->serverCredentials(), Protocol::Any);
ErrorCode e = ServerController::removeServer(m_settings.serverCredentials(), Protocol::Any);
if (e) {
QMessageBox::warning(this, APPLICATION_NAME,
tr("Error occurred while configuring server.") + "\n" +
@ -342,12 +372,12 @@ void MainWindow::onPushButtonForgetServer(bool)
{
onDisconnect();
m_settings->setUserName("");
m_settings->setPassword("");
m_settings->setServerName("");
m_settings->setServerPort();
m_settings.setUserName("");
m_settings.setPassword("");
m_settings.setServerName("");
m_settings.setServerPort();
m_settings->save();
m_settings.save();
goToPage(Page::Start);
}
@ -483,6 +513,7 @@ void MainWindow::setupUiConnections()
connect(ui->pushButton_connect, SIGNAL(clicked(bool)), this, SLOT(onPushButtonConnectClicked(bool)));
connect(ui->pushButton_new_server_setup, &QPushButton::clicked, this, [this](){ goToPage(Page::NewServer); });
connect(ui->pushButton_new_server_connect_with_new_data, SIGNAL(clicked(bool)), this, SLOT(onPushButtonNewServerConnectWithNewData(bool)));
connect(ui->pushButton_new_server_connect, SIGNAL(clicked(bool)), this, SLOT(onPushButtonNewServerConnectWithExistingCode(bool)));
connect(ui->pushButton_server_settings_reinstall, SIGNAL(clicked(bool)), this, SLOT(onPushButtonReinstallServer(bool)));
connect(ui->pushButton_server_settings_clear, SIGNAL(clicked(bool)), this, SLOT(onPushButtonClearServer(bool)));
@ -491,7 +522,19 @@ void MainWindow::setupUiConnections()
connect(ui->pushButton_blocked_list, &QPushButton::clicked, this, [this](){ goToPage(Page::Sites); });
connect(ui->pushButton_settings, &QPushButton::clicked, this, [this](){ goToPage(Page::GeneralSettings); });
connect(ui->pushButton_server_settings, &QPushButton::clicked, this, [this](){ goToPage(Page::ServerSettings); });
connect(ui->pushButton_share_connection, &QPushButton::clicked, this, [this](){ goToPage(Page::ShareConnection); });
connect(ui->pushButton_share_connection, &QPushButton::clicked, this, [this](){
goToPage(Page::ShareConnection);
updateShareCode();
});
connect(ui->pushButton_copy_sharing_code, &QPushButton::clicked, this, [this](){
QGuiApplication::clipboard()->setText(ui->textEdit_sharing_code->toPlainText());
ui->pushButton_copy_sharing_code->setText(tr("Copied"));
QTimer::singleShot(3000, [this]() {
ui->pushButton_copy_sharing_code->setText(tr("Copy"));
});
});
connect(ui->pushButton_back_from_sites, &QPushButton::clicked, this, [this](){ goToPage(Page::Vpn); });
@ -500,6 +543,8 @@ void MainWindow::setupUiConnections()
connect(ui->pushButton_back_from_server_settings, &QPushButton::clicked, this, [this](){ goToPage(Page::GeneralSettings); });
connect(ui->pushButton_back_from_share, &QPushButton::clicked, this, [this](){ goToPage(Page::GeneralSettings); });
connect(ui->pushButton_sites_add_custom, &QPushButton::clicked, this, [this](){ onPushButtonAddCustomSitesClicked(); });
connect(ui->pushButton_sites_delete_custom, &QPushButton::clicked, this, [this](){ onPushButtonDeleteCustomSiteClicked(); });
}
void MainWindow::setTrayState(VpnProtocol::ConnectionState state)
@ -564,7 +609,7 @@ void MainWindow::onConnect()
qApp->processEvents();
// TODO: Call connectToVpn with restricted server account
ServerCredentials credentials = m_settings->serverCredentials();
ServerCredentials credentials = m_settings.serverCredentials();
ErrorCode errorCode = m_vpnConnection->connectToVpn(credentials);
if (errorCode) {
@ -591,3 +636,89 @@ void MainWindow::onTrayActionConnect()
}
}
void MainWindow::onPushButtonAddCustomSitesClicked()
{
QString newSite = ui->lineEdit_sites_add_custom->text();
if (newSite.isEmpty()) return;
if (!newSite.contains(".")) return;
// get domain name if it present
newSite.replace("https://", "");
newSite.replace("http://", "");
newSite.replace("ftp://", "");
newSite = newSite.split("/", QString::SkipEmptyParts).first();
QStringList customSites = m_settings.customSites();
if (!customSites.contains(newSite)) {
customSites.append(newSite);
m_settings.setCustomSites(customSites);
QString newIp = Utils::getIPAddress(newSite);
QStringList customIps = m_settings.customIps();
if (!newIp.isEmpty() && !customIps.contains(newIp)) {
customIps.append(newIp);
m_settings.setCustomIps(customIps);
// add to routes immediatelly
// if (vpnStatus() == VPNStatusConnected) {
// //Router::Instance().routeAdd(newIp, vpnGate());
// }
}
initCustomSites();
ui->lineEdit_sites_add_custom->clear();
}
else {
qDebug() << "customSites already contains" << newSite;
}
}
void MainWindow::onPushButtonDeleteCustomSiteClicked()
{
QModelIndex index = ui->listView_sites_custom->currentIndex();
QString siteToDelete = index.data(Qt::DisplayRole).toString();
if (siteToDelete.isEmpty()) {
return;
}
QString ipToDelete = Utils::getIPAddress(siteToDelete);
QStringList customSites = m_settings.customSites();
customSites.removeAll(siteToDelete);
qDebug() << "Deleted custom site:" << siteToDelete;
m_settings.setCustomSites(customSites);
QStringList customIps = m_settings.customIps();
customIps.removeAll(ipToDelete);
qDebug() << "Deleted custom ip:" << ipToDelete;
m_settings.setCustomIps(customIps);
initCustomSites();
//Router::Instance().routeDelete(Utils::getIPAddress(ipToDelete));
//Router::Instance().flushDns();
}
void MainWindow::initCustomSites()
{
customSitesModel->setStringList(m_settings.customSites());
}
void MainWindow::updateShareCode()
{
QJsonObject o;
o.insert("h", m_settings.serverName());
o.insert("p", m_settings.serverPort());
o.insert("u", m_settings.userName());
o.insert("w", m_settings.password());
QByteArray ba = QJsonDocument(o).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
ui->textEdit_sharing_code->setText(QString("vpn://%1").arg(QString(ba)));
}

View file

@ -5,12 +5,14 @@
#include <QMainWindow>
#include <QProgressBar>
#include <QPushButton>
#include <QStringListModel>
#include <QSystemTrayIcon>
#include "framelesswindow.h"
#include "protocols/vpnprotocol.h"
class Settings;
#include "settings.h"
class VpnConnection;
namespace Ui {
@ -43,11 +45,15 @@ private slots:
void onPushButtonConnectClicked(bool checked);
void onPushButtonNewServerConnectWithNewData(bool);
void onPushButtonNewServerConnectWithExistingCode(bool);
void onPushButtonReinstallServer(bool);
void onPushButtonClearServer(bool);
void onPushButtonForgetServer(bool);
void onPushButtonAddCustomSitesClicked();
void onPushButtonDeleteCustomSiteClicked();
void onTrayActionConnect(); // connect from context menu
void setTrayState(VpnProtocol::ConnectionState state);
@ -68,10 +74,14 @@ private:
void setTrayIcon(const QString &iconPath);
void setupUiConnections();
void initCustomSites();
void updateShareCode();
Ui::MainWindow *ui;
VpnConnection* m_vpnConnection;
Settings* m_settings;
Settings m_settings;
QAction* m_trayActionConnect;
QAction* m_trayActionDisconnect;
@ -79,6 +89,8 @@ private:
QSystemTrayIcon m_tray;
QMenu* m_menu;
QStringListModel *customSitesModel = nullptr;
bool canMove = false;
QPoint offset;
bool eventFilter(QObject *obj, QEvent *event) override;

View file

@ -14,8 +14,7 @@
<string/>
</property>
<property name="styleSheet">
<string notr="true">/*----------------------*/
<string notr="true">
QLabel {
color: #181922;
}
@ -257,17 +256,10 @@ QPushButton:hover {
</rect>
</property>
<property name="styleSheet">
<string notr="true">QStackedWidget#stackedWidget_main{
background: transparent;
}
QStackedWidget QWidget {
background: transparent;
}
</string>
<string notr="true"/>
</property>
<property name="currentIndex">
<number>2</number>
<number>0</number>
</property>
<widget class="QWidget" name="page_start">
<widget class="QLabel" name="label_23">
@ -365,7 +357,7 @@ border-radius: 4px;</string>
<string/>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_new_server_ip_3">
<widget class="QLineEdit" name="lineEdit_start_existing_code">
<property name="geometry">
<rect>
<x>40</x>
@ -384,6 +376,9 @@ color: #333333;</string>
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>vpn://...</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_new_server_connect">
<property name="geometry">
@ -1162,17 +1157,18 @@ color: #181922;
<bool>true</bool>
</property>
</widget>
<widget class="QLabel" name="label_tmp_logo">
<widget class="QLabel" name="label_19">
<property name="geometry">
<rect>
<x>0</x>
<y>500</y>
<width>381</width>
<height>131</height>
<x>10</x>
<y>460</y>
<width>361</width>
<height>141</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/images/AmneziaVPN.png);</string>
<string notr="true">image: url(:/images/AmneziaVPN.png);
background-color: rgb(255, 255, 255);</string>
</property>
<property name="text">
<string/>
@ -1303,7 +1299,7 @@ line-height: 25px;
color: #181922;</string>
</property>
<property name="text">
<string>These sites will open via VPN</string>
<string>These sites will be opened using VPN</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
@ -1360,7 +1356,7 @@ border: 1px solid #A7A7A7;
<set>Qt::AlignCenter</set>
</property>
<property name="placeholderText">
<string>For example, rutor.org or 17.21.111.8</string>
<string>For example, yousite.com or 17.21.111.8</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_sites_add_custom">
@ -1379,10 +1375,10 @@ border: 1px solid #A7A7A7;
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="styleSheet">
<string notr="true">/* black */
background: #181922;
<string notr="true">background: #100A44;
border-radius: 4px;
font-size: 18pt;</string>
font-size: 24px;
color: white</string>
</property>
<property name="text">
<string>+</string>
@ -1407,7 +1403,7 @@ font-size: 18pt;</string>
<string notr="true">color: #181922;</string>
</property>
<property name="text">
<string>Delete selected item</string>
<string>Delete selected site</string>
</property>
</widget>
<widget class="QLabel" name="label_3">
@ -1432,7 +1428,7 @@ line-height: 150%;
color: #333333;</string>
</property>
<property name="text">
<string>Hostname or IP address</string>
<string>Web site or hostname or IP address</string>
</property>
</widget>
</widget>
@ -1947,6 +1943,9 @@ color: #333333;</string>
<zorder>label_server_settings_server</zorder>
</widget>
<widget class="QWidget" name="page_share_connection">
<property name="styleSheet">
<string notr="true"/>
</property>
<widget class="QPushButton" name="pushButton_back_from_share">
<property name="geometry">
<rect>
@ -2013,17 +2012,19 @@ color: #181922;</string>
<bool>true</bool>
</property>
</widget>
<widget class="QTextEdit" name="textEdit">
<widget class="QTextEdit" name="textEdit_sharing_code">
<property name="geometry">
<rect>
<x>30</x>
<y>100</y>
<width>320</width>
<height>151</height>
<height>211</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background: #F5F5F5;
<string notr="true">QTextEdit {
background: #F5F5F5;
border-radius: 10px;
@ -2036,27 +2037,32 @@ line-height: 110%;
text-align: center;
color: #15CDCB;
}
</string>
</property>
<property name="lineWrapMode">
<enum>QTextEdit::FixedColumnWidth</enum>
</property>
<property name="lineWrapColumnOrWidth">
<number>20</number>
<number>30</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Consolas'; font-size:22px; font-weight:600; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:20pt;&quot;&gt;vpn:\\aosdiufhafafsuhgqejghuserhglaidhgauhgalgadg&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:20pt;&quot;&gt;vpn:\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_blocked_list_2">
<widget class="QPushButton" name="pushButton_copy_sharing_code">
<property name="geometry">
<rect>
<x>20</x>
<y>280</y>
<y>340</y>
<width>341</width>
<height>40</height>
</rect>
@ -2090,7 +2096,7 @@ line-height: 21px;
<property name="geometry">
<rect>
<x>30</x>
<y>350</y>
<y>400</y>
<width>321</width>
<height>101</height>
</rect>

View file

@ -111,3 +111,71 @@ bool Utils::processIsRunning(const QString& fileName)
#endif
}
QString Utils::getIPAddress(const QString& host)
{
//TODO rewrite to api calls
qDebug().noquote() << "GetIPAddress: checking " + host;
if(host.isEmpty()) {
qDebug().noquote() << "GetIPAddress: host is empty.";
return QString();
}
if(checkIPFormat(host)) {
qDebug().noquote() << "GetIPAddress host is ip:" << host << host;
return host; // it is a ip address.
}
QProcess ping;
#ifdef Q_OS_MACX
ping.start("ping", QStringList() << "-c1" << host);
#endif
#ifdef Q_OS_WIN
ping.start("ping", QStringList() << QString("/n") << "1" << QString("/w") << "1" << host);
#endif
ping.waitForStarted();
QEventLoop loop;
loop.connect(&ping, SIGNAL(finished(int)), &loop, SLOT(quit()));
loop.exec();
QString d = ping.readAll();
if(d.size() == 0)
return QString();
qDebug().noquote() << d;
QString ip;
#ifdef Q_OS_MACX
ip = getStringBetween(d, "(", ")");
#endif
#ifdef Q_OS_WIN
ip = getStringBetween(d, "[", "]");
#endif
qDebug().noquote() << "GetIPAddress:" << host << ip;
return ip;
}
QString Utils::getStringBetween(const QString& s, const QString& a, const QString& b)
{
int ap = s.indexOf(a), bp = s.indexOf(b, ap + a.length());
if(ap < 0 || bp < 0)
return QString();
ap += a.length();
if(bp - ap <= 0)
return QString();
return s.mid(ap, bp - ap).trimmed();
}
bool Utils::checkIPFormat(const QString& ip)
{
int count = ip.count(".");
if(count != 3)
return false;
QStringList list = ip.trimmed().split(".");
foreach(QString it, list) {
if(it.toInt() <= 255 && it.toInt() >= 0)
continue;
return false;
}
return true;
}

View file

@ -15,6 +15,10 @@ public:
static bool createEmptyFile(const QString& path);
static bool initializePath(const QString& path);
static bool processIsRunning(const QString& fileName);
static QString getIPAddress(const QString& host);
static QString getStringBetween(const QString& s, const QString& a, const QString& b);
static bool checkIPFormat(const QString& ip);
};
#endif // UTILS_H

View file

@ -9,6 +9,7 @@
#include "protocols/shadowsocksvpnprotocol.h"
#include "utils.h"
#include "vpnconnection.h"
#include "communicator.h"
VpnConnection::VpnConnection(QObject* parent) : QObject(parent)
{
@ -22,6 +23,25 @@ void VpnConnection::onBytesChanged(quint64 receivedBytes, quint64 sentBytes)
void VpnConnection::onConnectionStateChanged(VpnProtocol::ConnectionState state)
{
// if (state == VpnProtocol::ConnectionState::Connected){
// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::FlushDnsRequest, QStringList()));
// // add routes
// const QStringList &black_custom = m_settings.customIps();
// qDebug() << "onConnect :: adding custom black routes, count:" << black_custom.size();
// QStringList args;
// args << m_vpnProtocol->vpnGateway();
// args << black_custom;
// Message m(Message::State::RoutesAddRequest, args);
// m_vpnProtocol->communicator()->sendMessage(m);
// }
// else if (state == VpnProtocol::ConnectionState::Error) {
// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::ClearSavedRoutesRequest, QStringList()));
// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::FlushDnsRequest, QStringList()));
// }
emit connectionStateChanged(state);
}
@ -113,6 +133,9 @@ void VpnConnection::disconnectFromVpn()
{
qDebug() << "Disconnect from VPN";
// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::ClearSavedRoutesRequest, QStringList()));
// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::FlushDnsRequest, QStringList()));
if (!m_vpnProtocol.data()) {
return;
}

View file

@ -7,6 +7,7 @@
#include "protocols/vpnprotocol.h"
#include "core/defs.h"
#include "settings.h"
using namespace amnezia;
@ -41,6 +42,9 @@ protected slots:
protected:
QScopedPointer<VpnProtocol> m_vpnProtocol;
private:
Settings m_settings;
};
#endif // VPNCONNECTION_H