Skip to content

Commit

Permalink
feat: enhance README and settings for system proxy configuration
Browse files Browse the repository at this point in the history
- Updated README to provide clearer instructions for Windows, macOS, and Linux users on downloading and running the application.
- Added a new input field for "System Proxy Bypass" in the settings window to allow users to specify hosts to bypass the proxy.
- Modified the proxy settings logic to include the bypass configuration for Linux and Windows systems.
- Adjusted UI layout to accommodate the new settings and improved overall usability.
  • Loading branch information
chenx-dust committed Jan 9, 2025
1 parent 0040ea8 commit 39ec3c9
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 17 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@

## 使用方式

1. 在本项目的 [Releases](https://github.com/chenx-dust/HITsz-Connect-for-Windows/releases) 页面下载最新版本,将所有文件解压至同一目录下,运行 `HITszConnectForWindows.exe`
1. 在本项目的 [Releases](https://github.com/chenx-dust/HITsz-Connect-for-Windows/releases) 页面下载最新版本:

- **Windows 用户**:下载 `HITsz-Connect-for-Windows-vX.X.X-windows-ARCH.zip` ,解压至同一目录下,双击运行 `HITszConnectForWindows.exe`
- **macOS 用户**:下载 `HITsz-Connect-for-Windows-vX.X.X-macOS-ARCH.dmg` ,按照镜像内部指示安装,并运行修复脚本;
- 如果你遇到“Apple 无法检查 App 是否包含恶意软件”等报错,请参考: [Apple 支持](https://support.apple.com/zh-cn/guide/mac-help/mchleab3a043/mac)
- **Linux 用户**:下载 `HITsz-Connect-for-Windows-vX.X.X-linux-ARCH.AppImage` ,赋予执行权限,运行即可;
- AppImage 仅支持系统 `glibc >= 2.31` 的发行版,Ubuntu 20.04 及以上版本可以正常运行;
- Arch Linux 用户请等待 AUR 包的提交;
- 如果遇到因依赖问题无法运行的情况,请自行编译运行。

<div align="center">
<img src="docs/main.png" width="600px">
Expand Down
2 changes: 2 additions & 0 deletions settingwindow/settingwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ SettingWindow::SettingWindow(QWidget *parent, QSettings *inputSettings) :
settings->setValue("ZJUConnect/Route", ui->routeCheckBox->isChecked());
settings->setValue("ZJUConnect/SecondaryDNS", ui->secondaryDnsLineEdit->text());
settings->setValue("ZJUConnect/ShadowsocksUrl", ui->shadowsocksUrlLineEdit->text());
settings->setValue("ZJUConnect/SystemProxyBypass", ui->systemProxyBypassLineEdit->text());
settings->setValue("ZJUConnect/KeepAlive", ui->keepAliveCheckBox->isChecked());
settings->setValue("ZJUConnect/TunMode", ui->tunCheckBox->isChecked());
settings->setValue("ZJUConnect/DNSHijack", ui->dnsHijackCheckBox->isChecked());
Expand Down Expand Up @@ -142,6 +143,7 @@ void SettingWindow::loadSettings()
ui->routeCheckBox->setChecked(settings->value("ZJUConnect/Route", false).toBool());
ui->secondaryDnsLineEdit->setText(settings->value("ZJUConnect/SecondaryDNS", "").toString());
ui->shadowsocksUrlLineEdit->setText(settings->value("ZJUConnect/ShadowsocksUrl", "").toString());
ui->systemProxyBypassLineEdit->setText(settings->value("ZJUConnect/SystemProxyBypass", "localhost;127.*;::1").toString());
ui->keepAliveCheckBox->setChecked(settings->value("ZJUConnect/KeepAlive", true).toBool());
ui->tunCheckBox->setChecked(settings->value("ZJUConnect/TunMode", false).toBool());
ui->dnsHijackCheckBox->setChecked(settings->value("ZJUConnect/DNSHijack", false).toBool());
Expand Down
20 changes: 17 additions & 3 deletions settingwindow/settingwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>486</width>
<height>406</height>
<height>433</height>
</rect>
</property>
<property name="windowTitle">
Expand All @@ -23,7 +23,7 @@
<locale language="Chinese" country="China"/>
</property>
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="commonTab">
<attribute name="title">
Expand Down Expand Up @@ -419,7 +419,7 @@
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="zjuConnectTabLabel7_2">
<widget class="QLabel" name="zjuConnectTabLabel10">
<property name="text">
<string>Shadowsocks 服务器</string>
</property>
Expand All @@ -432,6 +432,20 @@
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="zjuConnectTabLabel11">
<property name="text">
<string>系统代理排除</string>
</property>
</widget>
</item>
<item row="7" column="1" colspan="3">
<widget class="QLineEdit" name="systemProxyBypassLineEdit">
<property name="placeholderText">
<string>用半角分号;进行分隔</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
Expand Down
182 changes: 171 additions & 11 deletions utils/proxysettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <QProcess>
#include <QMessageBox>
#include <QSettings>
#include <QStandardPaths>
#include "utils.h"

#if defined(Q_OS_WINDOWS)
Expand Down Expand Up @@ -255,6 +256,168 @@ void macOSSetProxyBypass(const QString &networkService, const QString &bypass)
}
}

using ProcessArgument = QPair<QString, QStringList>;

void linuxSetSystemProxy(const QString &proxyServer, int httpPort, int socksPort, const QString &bypass)
{
QList<ProcessArgument> actions;
actions << ProcessArgument{"gsettings", {"set", "org.gnome.system.proxy", "mode", "manual"}};
//
bool isKDE = qEnvironmentVariable("XDG_SESSION_DESKTOP") == "KDE" ||
qEnvironmentVariable("XDG_SESSION_DESKTOP") == "plasma";
const auto configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);

//
// Configure HTTP Proxies for HTTP, FTP and HTTPS
// if (hasHTTP)
{
// iterate over protocols...
for (const auto &protocol : QStringList{"http", "ftp", "https"})
{
// for GNOME:
{
actions << ProcessArgument{"gsettings",
{"set", "org.gnome.system.proxy." + protocol, "host", proxyServer}};
actions << ProcessArgument{"gsettings",
{"set", "org.gnome.system.proxy." + protocol, "port", QString::number(httpPort)}};
}

// for KDE:
if (isKDE)
{
actions << ProcessArgument{"kwriteconfig5",
{"--file", configPath + "/kioslaverc", //
"--group", "Proxy Settings", //
"--key", protocol + "Proxy", //
"http://" + proxyServer + " " + QString::number(httpPort)}};
}
}
}

// Configure SOCKS5 Proxies
// if (hasSOCKS)
{
// for GNOME:
{
actions << ProcessArgument{"gsettings", {"set", "org.gnome.system.proxy.socks", "host", proxyServer}};
actions << ProcessArgument{"gsettings",
{"set", "org.gnome.system.proxy.socks", "port", QString::number(socksPort)}};

// for KDE:
if (isKDE)
{
actions << ProcessArgument{"kwriteconfig5",
{"--file", configPath + "/kioslaverc", //
"--group", "Proxy Settings", //
"--key", "socksProxy", //
"socks://" + proxyServer + " " + QString::number(socksPort)}};
}
}
}
// Setting Proxy Mode to Manual
{
// for GNOME:
{
actions << ProcessArgument{"gsettings", {"set", "org.gnome.system.proxy", "mode", "manual"}};
QStringList bypassList = bypass.split(";");
QString ignoreHosts = "[\"" + bypassList.join("\",\"") + "\"]";
actions << ProcessArgument{"gsettings", {"set", "org.gnome.system.proxy", "ignore-hosts", ignoreHosts}};
}

// for KDE:
if (isKDE)
{
actions << ProcessArgument{"kwriteconfig5",
{"--file", configPath + "/kioslaverc", //
"--group", "Proxy Settings", //
"--key", "ProxyType", "1"}};
actions << ProcessArgument{"kwriteconfig5",
{"--file", configPath + "/kioslaverc", //
"--group", "Proxy Settings", //
"--key", "NoProxyFor", bypass}};
}
}

// Notify kioslaves to reload system proxy configuration.
if (isKDE)
{
actions << ProcessArgument{"dbus-send",
{"--type=signal", "/KIO/Scheduler", //
"org.kde.KIO.Scheduler.reparseSlaveConfiguration", //
"string:''"}};
}
// Execute them all!
//
// note: do not use std::all_of / any_of / none_of,
// because those are short-circuit and cannot guarantee atomicity.
QList<bool> results;
for (const auto &action : actions)
{
// execute and get the code
const auto returnCode = QProcess::execute(action.first, action.second);
// print out the commands and result codes
qDebug() << QStringLiteral("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";"));
// give the code back
results << (returnCode == QProcess::NormalExit);
}

if (results.count(true) != actions.size())
{
QMessageBox::critical(nullptr, "设置系统代理失败", "存在失败的命令");
}
}

void linuxClearSystemProxy()
{
QList<ProcessArgument> actions;
const bool isKDE = qEnvironmentVariable("XDG_SESSION_DESKTOP") == "KDE" ||
qEnvironmentVariable("XDG_SESSION_DESKTOP") == "plasma";
const auto configRoot = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);

// Setting System Proxy Mode to: None
{
// for GNOME:
{
actions << ProcessArgument{"gsettings", {"set", "org.gnome.system.proxy", "mode", "none"}};
}

// for KDE:
if (isKDE)
{
actions << ProcessArgument{"kwriteconfig5",
{"--file", configRoot + "/kioslaverc", //
"--group", "Proxy Settings", //
"--key", "ProxyType", "0"}};
}
}

// Notify kioslaves to reload system proxy configuration.
if (isKDE)
{
actions << ProcessArgument{"dbus-send",
{"--type=signal", "/KIO/Scheduler", //
"org.kde.KIO.Scheduler.reparseSlaveConfiguration", //
"string:''"}};
}

// Execute the Actions
for (const auto &action : actions)
{
// execute and get the code
const auto returnCode = QProcess::execute(action.first, action.second);
// print out the commands and result codes
qDebug() << QStringLiteral("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";"));
}
}

bool linuxIsSystemProxySet()
{
QProcess process;
process.start("gsettings", {"get", "org.gnome.system.proxy", "mode"});
process.waitForFinished();
return process.readAllStandardOutput().contains("manual");
}

bool Utils::isSystemProxySet()
{
#if defined(Q_OS_WINDOWS)
Expand All @@ -274,31 +437,28 @@ bool Utils::isSystemProxySet()
}
return false;
#elif defined(Q_OS_LINUX)
return false;
return linuxIsSystemProxySet();
#endif
}

void Utils::setSystemProxy(int http_port, int socks_port)
void Utils::setSystemProxy(int http_port, int socks_port, const QString &bypass)
{
#if defined(Q_OS_WINDOWS)
windowsSetProxyForAllConnections(
"127.0.0.1:" + QString::number(http_port),
"localhost;127.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;"
"172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;<local>");
bypass);
#elif defined(Q_OS_MACOS)
QStringList activeServices = macOSGetActiveNetworkServices();
for (const QString &service : activeServices)
{
macOSSetSystemProxy(macOSProxyType::WebProxy, service, "127.0.0.1", http_port);
macOSSetSystemProxy(macOSProxyType::SecureWebProxy, service, "127.0.0.1", http_port);
// macOSSetSystemProxy(macOSProxyType::SOCKSFirewallProxy, service, "127.0.0.1", socks_port);
macOSDisableSystemProxy(macOSProxyType::SOCKSFirewallProxy, service);
macOSSetProxyBypass(service, "localhost;127.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;"
"172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;<local>");
// 实测 SOCKS5 有 Bug,暂停使用
macOSSetSystemProxy(macOSProxyType::SOCKSFirewallProxy, service, "127.0.0.1", socks_port);
// macOSDisableSystemProxy(macOSProxyType::SOCKSFirewallProxy, service);
macOSSetProxyBypass(service, bypass);
}
#elif defined(Q_OS_LINUX)
return;
linuxSetSystemProxy("127.0.0.1", http_port, socks_port, bypass);
#endif
}

Expand All @@ -315,7 +475,7 @@ void Utils::clearSystemProxy()
macOSDisableSystemProxy(macOSProxyType::SOCKSFirewallProxy, service);
}
#elif defined(Q_OS_LINUX)
return;
linuxClearSystemProxy();
#endif
}

Expand Down
2 changes: 1 addition & 1 deletion utils/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace Utils

bool isSystemProxySet();

void setSystemProxy(int http_port, int socks_port);
void setSystemProxy(int http_port, int socks_port, const QString &bypass);

void clearSystemProxy();

Expand Down
3 changes: 2 additions & 1 deletion zjuconnectmode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ void MainWindow::initZjuConnect()
}

Utils::setSystemProxy(settings->value("ZJUConnect/HttpPort", 11081).toInt(),
settings->value("ZJUConnect/Socks5Port", 11080).toInt());
settings->value("ZJUConnect/Socks5Port", 11080).toInt(),
settings->value("ZJUConnect/SystemProxyBypass", "localhost;127.*;::1").toString());
ui->pushButton2->setText("清除系统代理");
isSystemProxySet = true;
}
Expand Down

0 comments on commit 39ec3c9

Please sign in to comment.