mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-17 20:44:38 +03:00
refactor vpn settings
fix: nekoray_core freedom udp loopback feat: copy custom config
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -80,3 +80,4 @@ CMakeLists.txt.user*
|
||||
|
||||
# Deploy
|
||||
/deployment
|
||||
/neko*.sh
|
||||
|
||||
@@ -181,6 +181,10 @@ set(PROJECT_SOURCES
|
||||
ui/dialog_manage_routes.h
|
||||
ui/dialog_manage_routes.ui
|
||||
|
||||
ui/dialog_vpn_settings.cpp
|
||||
ui/dialog_vpn_settings.h
|
||||
ui/dialog_vpn_settings.ui
|
||||
|
||||
ui/dialog_hotkey.cpp
|
||||
ui/dialog_hotkey.h
|
||||
ui/dialog_hotkey.ui
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#include "db/ConfigBuilder.hpp"
|
||||
#include "db/Database.hpp"
|
||||
#include "fmt/includes.h"
|
||||
#include "fmt/Preset.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace NekoRay {
|
||||
|
||||
@@ -694,7 +696,7 @@ namespace NekoRay {
|
||||
{"outbound", "dns-out"}};
|
||||
|
||||
// geopath
|
||||
auto geopath = NekoRay::dataStore->v2ray_asset_dir;
|
||||
auto geopath = dataStore->v2ray_asset_dir;
|
||||
if (geopath.isEmpty()) geopath = QApplication::applicationDirPath();
|
||||
auto geoip = geopath + "/geoip.db";
|
||||
auto geosite = geopath + "/geosite.db";
|
||||
@@ -714,4 +716,58 @@ namespace NekoRay {
|
||||
return result;
|
||||
}
|
||||
|
||||
QString WriteVPNSingBoxConfig() {
|
||||
//
|
||||
QString process_name_rule = dataStore->vpn_bypass_process.trimmed();
|
||||
if (!process_name_rule.isEmpty()) {
|
||||
auto arr = SplitLines(process_name_rule);
|
||||
QJsonObject rule{{"outbound", "direct"},
|
||||
{"process_name", QList2QJsonArray(arr)}};
|
||||
process_name_rule = "," + QJsonObject2QString(rule, false);
|
||||
}
|
||||
QString cidr_rule = dataStore->vpn_bypass_cidr.trimmed();
|
||||
if (!cidr_rule.isEmpty()) {
|
||||
auto arr = SplitLines(cidr_rule);
|
||||
QJsonObject rule{{"outbound", "direct"},
|
||||
{"ip_cidr", QList2QJsonArray(arr)}};
|
||||
cidr_rule = "," + QJsonObject2QString(rule, false);
|
||||
}
|
||||
// gen config
|
||||
auto configFn = ":/nekoray/vpn/sing-box-vpn.json";
|
||||
if (QFile::exists("vpn/sing-box-vpn.json")) configFn = "vpn/sing-box-vpn.json";
|
||||
auto config = ReadFileText(configFn)
|
||||
.replace("%IPV6_ADDRESS%", dataStore->vpn_ipv6 ? R"("inet6_address": "fdfe:dcba:9876::1/126",)" : "")
|
||||
.replace("%MTU%", Int2String(dataStore->vpn_mtu))
|
||||
.replace("%STACK%", Preset::SingBox::VpnImplementation.value(dataStore->vpn_implementation))
|
||||
.replace("%PROCESS_NAME_RULE%", process_name_rule)
|
||||
.replace("%CIDR_RULE%", cidr_rule)
|
||||
.replace("%PORT%", Int2String(dataStore->inbound_socks_port));
|
||||
// write config
|
||||
QFile file;
|
||||
file.setFileName(QFileInfo(configFn).fileName());
|
||||
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
|
||||
file.write(config.toUtf8());
|
||||
file.close();
|
||||
return QFileInfo(file).absoluteFilePath();
|
||||
}
|
||||
|
||||
QString WriteVPNLinuxScript(const QString &protectPath, const QString &configPath) {
|
||||
// gen script
|
||||
auto scriptFn = ":/nekoray/vpn/vpn-run-root.sh";
|
||||
if (QFile::exists("vpn/vpn-run-root.sh")) scriptFn = "vpn/vpn-run-root.sh";
|
||||
auto script = ReadFileText(scriptFn)
|
||||
.replace("$PORT", Int2String(dataStore->inbound_socks_port))
|
||||
.replace("./nekobox_core", QApplication::applicationDirPath() + "/nekobox_core")
|
||||
.replace("$PROTECT_LISTEN_PATH", protectPath)
|
||||
.replace("$CONFIG_PATH", configPath)
|
||||
.replace("$TABLE_FWMARK", "514");
|
||||
// write script
|
||||
QFile file2;
|
||||
file2.setFileName(QFileInfo(scriptFn).fileName());
|
||||
file2.open(QIODevice::ReadWrite | QIODevice::Truncate);
|
||||
file2.write(script.toUtf8());
|
||||
file2.close();
|
||||
return QFileInfo(file2).absoluteFilePath();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -51,4 +51,8 @@ namespace NekoRay {
|
||||
|
||||
QString BuildChainInternal(int chainId, const QList<QSharedPointer<ProxyEntity>> &ents,
|
||||
const QSharedPointer<BuildConfigStatus> &status);
|
||||
|
||||
QString WriteVPNSingBoxConfig();
|
||||
|
||||
QString WriteVPNLinuxScript(const QString &protectPath, const QString &configPath);
|
||||
}
|
||||
|
||||
@@ -22,9 +22,14 @@
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block"
|
||||
},
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"auto_detect_interface": true,
|
||||
"rules": [
|
||||
{
|
||||
"network": "udp",
|
||||
@@ -36,7 +41,23 @@
|
||||
5353
|
||||
],
|
||||
"outbound": "block"
|
||||
},
|
||||
{
|
||||
"ip_cidr": [
|
||||
"224.0.0.0/4",
|
||||
"ff00::/8"
|
||||
],
|
||||
"outbound": "block"
|
||||
},
|
||||
{
|
||||
"source_ip_cidr": [
|
||||
"224.0.0.0/4",
|
||||
"ff00::/8"
|
||||
],
|
||||
"outbound": "block"
|
||||
}
|
||||
%PROCESS_NAME_RULE%
|
||||
%CIDR_RULE%
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ namespace NekoRay::fmt {
|
||||
QStringList env;
|
||||
QStringList arguments;
|
||||
QString error;
|
||||
QString config_export;
|
||||
};
|
||||
|
||||
class AbstractBean : public JsonStore {
|
||||
@@ -38,6 +39,8 @@ namespace NekoRay::fmt {
|
||||
|
||||
[[nodiscard]] virtual QString DisplayName();
|
||||
|
||||
virtual QString DisplayCoreType() { return software_core_name; };
|
||||
|
||||
virtual QString DisplayType() { return {}; };
|
||||
|
||||
virtual QString DisplayTypeAndName();
|
||||
|
||||
@@ -26,14 +26,17 @@ namespace NekoRay::fmt {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto _serverAddress = sni.isEmpty() ? serverAddress : sni;
|
||||
auto is_export = mapping_port == 114514;
|
||||
auto domain_address = sni.isEmpty() ? serverAddress : sni;
|
||||
auto connect_address = is_export ? serverAddress : "127.0.0.1";
|
||||
auto connect_port = is_export ? serverPort : mapping_port;
|
||||
|
||||
result.arguments += "--log";
|
||||
result.arguments += "--listen=socks://127.0.0.1:" + Int2String(socks_port);
|
||||
result.arguments += "--proxy=" + protocol + "://" +
|
||||
username + ":" + password + "@" +
|
||||
_serverAddress + ":" + Int2String(mapping_port);
|
||||
result.arguments += "--host-resolver-rules=MAP " + _serverAddress + " 127.0.0.1";
|
||||
result.arguments += "--proxy=" + protocol + "://" + username + ":" + password + "@" +
|
||||
domain_address + ":" + Int2String(connect_port);
|
||||
if (domain_address != connect_address)
|
||||
result.arguments += "--host-resolver-rules=MAP " + domain_address + " " + connect_address;
|
||||
if (insecure_concurrency > 0) result.arguments += "--insecure-concurrency=" + Int2String(insecure_concurrency);
|
||||
if (!extra_headers.isEmpty()) result.arguments += "--extra-headers=" + extra_headers;
|
||||
if (!certificate.isEmpty()) {
|
||||
@@ -41,6 +44,10 @@ namespace NekoRay::fmt {
|
||||
result.env += "SSL_CERT_FILE=" + TempFile;
|
||||
}
|
||||
|
||||
auto config_export = QStringList{result.program};
|
||||
config_export += result.arguments;
|
||||
result.config_export = QStringList2Command(config_export);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -74,6 +81,8 @@ namespace NekoRay::fmt {
|
||||
for (int i = 0; i < result.arguments.count(); i++) {
|
||||
result.arguments[i] = result.arguments[i].replace("%config%", TempFile);
|
||||
}
|
||||
|
||||
result.config_export = config;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace NekoRay::fmt {
|
||||
|
||||
QString DisplayType() override { return core; };
|
||||
|
||||
QString DisplayCoreType() override { return NeedExternal() ? core : software_core_name; };
|
||||
|
||||
bool NeedExternal() override {
|
||||
if (IS_NEKO_BOX && core == "hysteria") return false;
|
||||
return true;
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace NekoRay::fmt {
|
||||
_add(new configItem("insecure_concurrency", &insecure_concurrency, itemType::integer));
|
||||
};
|
||||
|
||||
QString DisplayCoreType() override { return "Naive"; };
|
||||
|
||||
QString DisplayType() override { return "Naive"; };
|
||||
|
||||
bool NeedExternal() override { return true; };
|
||||
|
||||
@@ -71,7 +71,7 @@ func updateRoutes() {
|
||||
|
||||
func getBindInterfaceIndex(address string) uint32 {
|
||||
host, _, _ := net.SplitHostPort(address)
|
||||
if !net.ParseIP(host).IsGlobalUnicast() {
|
||||
if net.ParseIP(host).IsLoopback() {
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ inline QMenu *CreateMenu(QWidget *parent, const QList<QString> &texts, const std
|
||||
#define P_SAVE_STRING_QTEXTEDIT(a) bean->a = ui->a->toPlainText();
|
||||
#define D_LOAD_STRING(a) ui->a->setText(NekoRay::dataStore->a);
|
||||
#define D_SAVE_STRING(a) NekoRay::dataStore->a = ui->a->text();
|
||||
#define D_SAVE_STRING_QTEXTEDIT(a) NekoRay::dataStore->a = ui->a->toPlainText();
|
||||
#define P_C_LOAD_STRING(a) CACHE.a = bean->a;
|
||||
#define P_C_SAVE_STRING(a) bean->a = CACHE.a;
|
||||
#define D_C_LOAD_STRING(a) CACHE.a = NekoRay::dataStore->a;
|
||||
|
||||
@@ -53,6 +53,8 @@ namespace NekoRay {
|
||||
_add(new configItem("vpn_mtu", &vpn_mtu, itemType::integer));
|
||||
_add(new configItem("vpn_ipv6", &vpn_ipv6, itemType::boolean));
|
||||
_add(new configItem("vpn_hide_console", &vpn_hide_consloe, itemType::boolean));
|
||||
_add(new configItem("vpn_bypass_process", &vpn_bypass_process, itemType::string));
|
||||
_add(new configItem("vpn_bypass_cidr", &vpn_bypass_cidr, itemType::string));
|
||||
_add(new configItem("check_include_pre", &check_include_pre, itemType::boolean));
|
||||
_add(new configItem("neko_core", &neko_core, itemType::integer));
|
||||
}
|
||||
|
||||
@@ -109,6 +109,8 @@ namespace NekoRay {
|
||||
int vpn_mtu = 9000;
|
||||
bool vpn_ipv6 = false;
|
||||
bool vpn_hide_consloe = false;
|
||||
QString vpn_bypass_process = "";
|
||||
QString vpn_bypass_cidr = "";
|
||||
|
||||
// Hotkey
|
||||
QString hotkey_mainwindow = "";
|
||||
|
||||
@@ -35,6 +35,15 @@ inline QString SubStrAfter(QString str, const QString &sub) {
|
||||
return str.right(str.length() - str.indexOf(sub) - sub.length());
|
||||
}
|
||||
|
||||
inline QString QStringList2Command(const QStringList &list) {
|
||||
QStringList new_list;
|
||||
for (auto str: list) {
|
||||
auto q = "\"" + str.replace("\"", "\\\"") + "\"";
|
||||
new_list << q;
|
||||
}
|
||||
return new_list.join(" ");
|
||||
}
|
||||
|
||||
inline QString
|
||||
DecodeB64IfValid(const QString &input, QByteArray::Base64Option options = QByteArray::Base64Option::Base64Encoding) {
|
||||
auto result = QByteArray::fromBase64Encoding(input.toUtf8(),
|
||||
|
||||
@@ -486,17 +486,32 @@
|
||||
<source>Custom (global)</source>
|
||||
<translation>自定义 (全局)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DialogVPNSettings</name>
|
||||
<message>
|
||||
<source>VPN Settings</source>
|
||||
<translation>VPN 设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>VPN Implementation</source>
|
||||
<translation>VPN 实现</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hide Console</source>
|
||||
<translation>隐藏控制台</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>VPN Enable IPv6</source>
|
||||
<translation>启用 VPN IPv6</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hide Console</source>
|
||||
<translation>隐藏控制台</translation>
|
||||
<source>Bypass CIDR</source>
|
||||
<translation>绕过 CIDR</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Bypass Process Name</source>
|
||||
<translation>绕过进程名</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -819,10 +834,6 @@
|
||||
<source>Stop</source>
|
||||
<translation>停止</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Routing VPN Settings</source>
|
||||
<translation>路由 VPN 设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Add profile from clipboard</source>
|
||||
<translation>从剪切板添加</translation>
|
||||
@@ -1029,10 +1040,6 @@ End: %2</source>
|
||||
<source>QR Code and link</source>
|
||||
<translation>显示 QR Code 和分享链接</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export V2ray config</source>
|
||||
<translation type="vanished">导出 V2ray 配置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Active Routing</source>
|
||||
<translation>当前路由规则</translation>
|
||||
@@ -1141,6 +1148,14 @@ End: %2</source>
|
||||
<source>Export %1 config</source>
|
||||
<translation>导出 %1 配置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Routing Settings</source>
|
||||
<translation>路由设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>VPN Settings</source>
|
||||
<translation>VPN 设置</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ProxyItem</name>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
|
||||
#include "qv2ray/v3/components/GeositeReader/GeositeReader.hpp"
|
||||
#include "fmt/Preset.hpp"
|
||||
#include "main/GuiUtils.hpp"
|
||||
|
||||
#include <QFile>
|
||||
@@ -31,11 +30,9 @@ DialogManageRoutes::DialogManageRoutes(QWidget *parent) :
|
||||
title_base = windowTitle();
|
||||
|
||||
if (IS_NEKO_BOX) {
|
||||
ui->fake_dns->setVisible(false);
|
||||
ui->enhance_resolve_server_domain->setVisible(false);
|
||||
ui->domain_v2ray->setVisible(false);
|
||||
} else {
|
||||
ui->fake_dns->setVisible(true);
|
||||
ui->enhance_resolve_server_domain->setVisible(true);
|
||||
ui->domain_v2ray->setVisible(true);
|
||||
}
|
||||
@@ -44,20 +41,11 @@ DialogManageRoutes::DialogManageRoutes(QWidget *parent) :
|
||||
ui->outbound_domain_strategy->setCurrentText(NekoRay::dataStore->outbound_domain_strategy);
|
||||
ui->domainMatcherCombo->setCurrentIndex(NekoRay::dataStore->domain_matcher);
|
||||
ui->domainStrategyCombo->setCurrentText(NekoRay::dataStore->domain_strategy);
|
||||
ui->fake_dns->setChecked(NekoRay::dataStore->fake_dns);
|
||||
ui->dns_routing->setChecked(NekoRay::dataStore->dns_routing);
|
||||
ui->dns_remote->setText(NekoRay::dataStore->remote_dns);
|
||||
ui->dns_direct->setText(NekoRay::dataStore->direct_dns);
|
||||
ui->enhance_resolve_server_domain->setChecked(NekoRay::dataStore->enhance_resolve_server_domain);
|
||||
D_C_LOAD_STRING(custom_route_global)
|
||||
//
|
||||
ui->vpn_implementation->setCurrentIndex(NekoRay::dataStore->vpn_implementation);
|
||||
ui->vpn_mtu->setCurrentText(Int2String(NekoRay::dataStore->vpn_mtu));
|
||||
ui->vpn_ipv6->setChecked(NekoRay::dataStore->vpn_ipv6);
|
||||
ui->hide_console->setChecked(NekoRay::dataStore->vpn_hide_consloe);
|
||||
#ifndef Q_OS_WIN
|
||||
ui->hide_console->setVisible(false);
|
||||
#endif
|
||||
//
|
||||
connect(ui->custom_route_edit, &QPushButton::clicked, this, [=] {
|
||||
C_EDIT_JSON_ALLOW_EMPTY(custom_route)
|
||||
@@ -113,25 +101,6 @@ void DialogManageRoutes::accept() {
|
||||
NekoRay::dataStore->direct_dns = ui->dns_direct->text();
|
||||
NekoRay::dataStore->enhance_resolve_server_domain = ui->enhance_resolve_server_domain->isChecked();
|
||||
D_C_SAVE_STRING(custom_route_global)
|
||||
//
|
||||
bool vpnChanged = false;
|
||||
auto fakedns = ui->fake_dns->isChecked();
|
||||
auto mtu = ui->vpn_mtu->currentText().toInt();
|
||||
if (mtu > 10000 || mtu < 1000) mtu = 9000;
|
||||
auto ipv6 = ui->vpn_ipv6->isChecked();
|
||||
//
|
||||
auto impl = ui->vpn_implementation->currentIndex();
|
||||
vpnChanged |= NekoRay::dataStore->vpn_implementation != impl;
|
||||
NekoRay::dataStore->vpn_implementation = impl;
|
||||
//
|
||||
vpnChanged |= NekoRay::dataStore->fake_dns != fakedns;
|
||||
vpnChanged |= NekoRay::dataStore->vpn_mtu != mtu;
|
||||
vpnChanged |= NekoRay::dataStore->vpn_ipv6 != ipv6;
|
||||
NekoRay::dataStore->fake_dns = fakedns;
|
||||
NekoRay::dataStore->vpn_mtu = mtu;
|
||||
NekoRay::dataStore->vpn_ipv6 = ipv6;
|
||||
NekoRay::dataStore->vpn_hide_consloe = ui->hide_console->isChecked();
|
||||
//
|
||||
bool routeChanged = false;
|
||||
if (NekoRay::dataStore->active_routing != active_routing) routeChanged = true;
|
||||
SAVE_TO_ROUTING(NekoRay::dataStore->routing)
|
||||
@@ -141,7 +110,6 @@ void DialogManageRoutes::accept() {
|
||||
//
|
||||
QString info = "UpdateDataStore";
|
||||
if (routeChanged) info += "RouteChanged";
|
||||
if (vpnChanged) info += "VPNChanged";
|
||||
dialog_message(Dialog_DialogManageRoutes, info);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ private:
|
||||
QString custom_route_global;
|
||||
} CACHE;
|
||||
|
||||
|
||||
QMenu *builtInSchemesMenu;
|
||||
Qv2ray::ui::widgets::AutoCompleteTextEdit *directDomainTxt;
|
||||
Qv2ray::ui::widgets::AutoCompleteTextEdit *proxyDomainTxt;
|
||||
@@ -41,6 +40,7 @@ private:
|
||||
//
|
||||
QString title_base;
|
||||
QString active_routing;
|
||||
|
||||
public slots:
|
||||
|
||||
void accept() override;
|
||||
|
||||
@@ -111,106 +111,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>VPN Implementation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="vpn_implementation">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">gVisor</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">System</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">MTU</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="vpn_mtu">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">9000</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">1500</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="hide_console">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Hide Console</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="vpn_ipv6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>VPN Enable IPv6</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="fake_dns">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">FakeDNS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
@@ -470,9 +370,6 @@
|
||||
<tabstops>
|
||||
<tabstop>sniffing_mode</tabstop>
|
||||
<tabstop>outbound_domain_strategy</tabstop>
|
||||
<tabstop>vpn_implementation</tabstop>
|
||||
<tabstop>vpn_mtu</tabstop>
|
||||
<tabstop>fake_dns</tabstop>
|
||||
<tabstop>dns_remote</tabstop>
|
||||
<tabstop>dns_direct</tabstop>
|
||||
<tabstop>enhance_resolve_server_domain</tabstop>
|
||||
|
||||
45
ui/dialog_vpn_settings.cpp
Normal file
45
ui/dialog_vpn_settings.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "dialog_vpn_settings.h"
|
||||
#include "ui_dialog_vpn_settings.h"
|
||||
|
||||
#include "main/GuiUtils.hpp"
|
||||
#include "main/NekoRay.hpp"
|
||||
|
||||
DialogVPNSettings::DialogVPNSettings(QWidget *parent) :
|
||||
QDialog(parent), ui(new Ui::DialogVPNSettings) {
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->fake_dns->setVisible(!IS_NEKO_BOX);
|
||||
ui->fake_dns->setChecked(NekoRay::dataStore->fake_dns);
|
||||
//
|
||||
ui->vpn_implementation->setCurrentIndex(NekoRay::dataStore->vpn_implementation);
|
||||
ui->vpn_mtu->setCurrentText(Int2String(NekoRay::dataStore->vpn_mtu));
|
||||
ui->vpn_ipv6->setChecked(NekoRay::dataStore->vpn_ipv6);
|
||||
ui->hide_console->setChecked(NekoRay::dataStore->vpn_hide_consloe);
|
||||
#ifndef Q_OS_WIN
|
||||
ui->hide_console->setVisible(false);
|
||||
#endif
|
||||
//
|
||||
D_LOAD_STRING(vpn_bypass_cidr)
|
||||
D_LOAD_STRING(vpn_bypass_process)
|
||||
}
|
||||
|
||||
DialogVPNSettings::~DialogVPNSettings() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void DialogVPNSettings::accept() {
|
||||
//
|
||||
auto mtu = ui->vpn_mtu->currentText().toInt();
|
||||
if (mtu > 10000 || mtu < 1000) mtu = 9000;
|
||||
NekoRay::dataStore->vpn_implementation = ui->vpn_implementation->currentIndex();
|
||||
NekoRay::dataStore->fake_dns = ui->fake_dns->isChecked();
|
||||
NekoRay::dataStore->vpn_mtu = mtu;
|
||||
NekoRay::dataStore->vpn_ipv6 = ui->vpn_ipv6->isChecked();
|
||||
NekoRay::dataStore->vpn_hide_consloe = ui->hide_console->isChecked();
|
||||
//
|
||||
D_SAVE_STRING_QTEXTEDIT(vpn_bypass_cidr)
|
||||
D_SAVE_STRING_QTEXTEDIT(vpn_bypass_process)
|
||||
//
|
||||
dialog_message("", "UpdateDataStore,VPNChanged");
|
||||
QDialog::accept();
|
||||
}
|
||||
29
ui/dialog_vpn_settings.h
Normal file
29
ui/dialog_vpn_settings.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef NEKORAY_DIALOG_VPN_SETTINGS_H
|
||||
#define NEKORAY_DIALOG_VPN_SETTINGS_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class DialogVPNSettings; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class DialogVPNSettings : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DialogVPNSettings(QWidget *parent = nullptr);
|
||||
|
||||
~DialogVPNSettings() override;
|
||||
|
||||
private:
|
||||
Ui::DialogVPNSettings *ui;
|
||||
|
||||
public slots:
|
||||
|
||||
void accept() override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //NEKORAY_DIALOG_VPN_SETTINGS_H
|
||||
194
ui/dialog_vpn_settings.ui
Normal file
194
ui/dialog_vpn_settings.ui
Normal file
@@ -0,0 +1,194 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DialogVPNSettings</class>
|
||||
<widget class="QDialog" name="DialogVPNSettings">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>VPN Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>VPN Implementation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="vpn_implementation">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">gVisor</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">System</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">MTU</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="vpn_mtu">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">9000</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">1500</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="horizontalGroupBox_2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="hide_console">
|
||||
<property name="text">
|
||||
<string>Hide Console</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="vpn_ipv6">
|
||||
<property name="text">
|
||||
<string>VPN Enable IPv6</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="fake_dns">
|
||||
<property name="text">
|
||||
<string notr="true">FakeDNS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="verticalGroupBox">
|
||||
<property name="title">
|
||||
<string>Bypass CIDR</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="vpn_bypass_cidr"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="verticalGroupBox_2">
|
||||
<property name="title">
|
||||
<string>Bypass Process Name</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="vpn_bypass_process"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>vpn_implementation</tabstop>
|
||||
<tabstop>vpn_mtu</tabstop>
|
||||
<tabstop>hide_console</tabstop>
|
||||
<tabstop>vpn_ipv6</tabstop>
|
||||
<tabstop>fake_dns</tabstop>
|
||||
<tabstop>vpn_bypass_cidr</tabstop>
|
||||
<tabstop>vpn_bypass_process</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>DialogVPNSettings</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>399</x>
|
||||
<y>575</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>399</x>
|
||||
<y>299</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>DialogVPNSettings</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>399</x>
|
||||
<y>575</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>399</x>
|
||||
<y>299</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "./ui_mainwindow.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include "fmt/Preset.hpp"
|
||||
#include "db/ProfileFilter.hpp"
|
||||
#include "db/ConfigBuilder.hpp"
|
||||
#include "sub/GroupUpdater.hpp"
|
||||
@@ -14,6 +13,7 @@
|
||||
#include "ui/dialog_basic_settings.h"
|
||||
#include "ui/dialog_manage_groups.h"
|
||||
#include "ui/dialog_manage_routes.h"
|
||||
#include "ui/dialog_vpn_settings.h"
|
||||
#include "ui/dialog_hotkey.h"
|
||||
|
||||
#include "3rdparty/qrcodegen.hpp"
|
||||
@@ -97,7 +97,6 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
if (IS_NEKO_BOX) {
|
||||
software_name = "NekoBox";
|
||||
software_core_name = "sing-box";
|
||||
ui->menu_export_config->setText(ui->menu_export_config->text().arg(software_core_name));
|
||||
}
|
||||
|
||||
// top bar
|
||||
@@ -342,6 +341,16 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
connect(ui->menu_tcp_ping, &QAction::triggered, this, [=]() { speedtest_current_group(0); });
|
||||
connect(ui->menu_url_test, &QAction::triggered, this, [=]() { speedtest_current_group(1); });
|
||||
connect(ui->menu_full_test, &QAction::triggered, this, [=]() { speedtest_current_group(2); });
|
||||
//
|
||||
connect(ui->menu_share_item, &QMenu::aboutToShow, this, [=] {
|
||||
auto name = software_core_name;
|
||||
auto selected = get_now_selected();
|
||||
if (!selected.isEmpty()) {
|
||||
auto ent = selected.first();
|
||||
name = ent->bean->DisplayCoreType();
|
||||
}
|
||||
ui->menu_export_config->setText(tr("Export %1 config").arg(name));
|
||||
});
|
||||
refresh_status();
|
||||
|
||||
// Prepare core
|
||||
@@ -499,6 +508,10 @@ void MainWindow::on_menu_routing_settings_triggered() {
|
||||
USE_DIALOG(DialogManageRoutes)
|
||||
}
|
||||
|
||||
void MainWindow::on_menu_vpn_settings_triggered() {
|
||||
USE_DIALOG(DialogVPNSettings)
|
||||
}
|
||||
|
||||
void MainWindow::on_menu_hotkey_settings_triggered() {
|
||||
USE_DIALOG(DialogHotkey)
|
||||
}
|
||||
@@ -987,8 +1000,16 @@ void MainWindow::on_menu_export_config_triggered() {
|
||||
auto ents = get_now_selected();
|
||||
if (ents.count() != 1) return;
|
||||
auto ent = ents.first();
|
||||
auto result = NekoRay::BuildConfig(ent, false);
|
||||
auto config_core = QJsonObject2QString(result->coreConfig, true);
|
||||
QString config_core;
|
||||
|
||||
if (ent->bean->NeedExternal()) {
|
||||
auto result = ent->bean->BuildExternal(114514, MkPort());
|
||||
config_core = result.config_export.replace("127.0.0.1:114514", ent->bean->DisplayAddress());
|
||||
} else {
|
||||
auto result = NekoRay::BuildConfig(ent, false);
|
||||
config_core = QJsonObject2QString(result->coreConfig, true);
|
||||
}
|
||||
|
||||
QApplication::clipboard()->setText(config_core);
|
||||
MessageBoxWarning(tr("Config copied"), config_core);
|
||||
}
|
||||
@@ -1406,39 +1427,10 @@ bool MainWindow::StartVPNProcess() {
|
||||
if (vpn_pid != 0) {
|
||||
return true;
|
||||
}
|
||||
// gen config
|
||||
auto configFn = ":/nekoray/vpn/sing-box-vpn.json";
|
||||
if (QFile::exists("vpn/sing-box-vpn.json")) configFn = "vpn/sing-box-vpn.json";
|
||||
auto config = ReadFileText(configFn)
|
||||
.replace("%IPV6_ADDRESS%",
|
||||
NekoRay::dataStore->vpn_ipv6 ? R"("inet6_address": "fdfe:dcba:9876::1/126",)" : "")
|
||||
.replace("%MTU%", Int2String(NekoRay::dataStore->vpn_mtu))
|
||||
.replace("%STACK%", Preset::SingBox::VpnImplementation.value(NekoRay::dataStore->vpn_implementation))
|
||||
.replace("%PORT%", Int2String(NekoRay::dataStore->inbound_socks_port));
|
||||
// write config
|
||||
QFile file;
|
||||
file.setFileName(QFileInfo(configFn).fileName());
|
||||
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
|
||||
file.write(config.toUtf8());
|
||||
file.close();
|
||||
auto configPath = QFileInfo(file).absoluteFilePath();
|
||||
// gen script
|
||||
//
|
||||
auto protectPath = QDir::currentPath() + "/protect";
|
||||
auto scriptFn = ":/nekoray/vpn/vpn-run-root.sh";
|
||||
if (QFile::exists("vpn/vpn-run-root.sh")) scriptFn = "vpn/vpn-run-root.sh";
|
||||
auto script = ReadFileText(scriptFn)
|
||||
.replace("$PORT", Int2String(NekoRay::dataStore->inbound_socks_port))
|
||||
.replace("./nekobox_core", QApplication::applicationDirPath() + "/nekobox_core")
|
||||
.replace("$PROTECT_LISTEN_PATH", protectPath)
|
||||
.replace("$CONFIG_PATH", configPath)
|
||||
.replace("$TABLE_FWMARK", "514");
|
||||
// write script
|
||||
QFile file2;
|
||||
file2.setFileName(QFileInfo(scriptFn).fileName());
|
||||
file2.open(QIODevice::ReadWrite | QIODevice::Truncate);
|
||||
file2.write(script.toUtf8());
|
||||
file2.close();
|
||||
auto scriptPath = QFileInfo(file2).absoluteFilePath();
|
||||
auto configPath = NekoRay::WriteVPNSingBoxConfig();
|
||||
auto scriptPath = NekoRay::WriteVPNLinuxScript(protectPath, configPath);
|
||||
//
|
||||
#ifdef Q_OS_WIN
|
||||
runOnNewThread([=] {
|
||||
|
||||
@@ -70,6 +70,8 @@ private slots:
|
||||
|
||||
void on_menu_routing_settings_triggered();
|
||||
|
||||
void on_menu_vpn_settings_triggered();
|
||||
|
||||
void on_menu_hotkey_settings_triggered();
|
||||
|
||||
void on_menu_add_from_input_triggered();
|
||||
|
||||
@@ -498,6 +498,7 @@
|
||||
<addaction name="menu_manage_groups"/>
|
||||
<addaction name="menu_basic_settings"/>
|
||||
<addaction name="menu_routing_settings"/>
|
||||
<addaction name="menu_vpn_settings"/>
|
||||
<addaction name="menu_hotkey_settings"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_server">
|
||||
@@ -590,7 +591,7 @@
|
||||
</action>
|
||||
<action name="menu_routing_settings">
|
||||
<property name="text">
|
||||
<string>Routing VPN Settings</string>
|
||||
<string>Routing Settings</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_add_from_clipboard">
|
||||
@@ -822,6 +823,11 @@
|
||||
<string>Resolve domain</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_vpn_settings">
|
||||
<property name="text">
|
||||
<string>VPN Settings</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
||||
Reference in New Issue
Block a user