From bbcd9df97762a4674170a1eb41756597b8ac2942 Mon Sep 17 00:00:00 2001 From: arm64v8a <48624112+arm64v8a@users.noreply.github.com> Date: Sun, 25 Sep 2022 13:12:29 +0800 Subject: [PATCH] refactor vpn settings fix: nekoray_core freedom udp loopback feat: copy custom config --- .gitignore | 1 + CMakeLists.txt | 4 + db/ConfigBuilder.cpp | 58 +++++- db/ConfigBuilder.hpp | 4 + examples/sing-box-vpn.json | 21 ++ fmt/AbstractBean.hpp | 3 + fmt/Bean2External.cpp | 19 +- fmt/CustomBean.hpp | 2 + fmt/NaiveBean.hpp | 2 + .../protect_bindinterface_windows.go | 2 +- main/GuiUtils.hpp | 1 + main/NekoRay.cpp | 2 + main/NekoRay_DataStore.hpp | 2 + main/NekoRay_Utils.hpp | 9 + translations/zh_CN.ts | 35 +++- ui/dialog_manage_routes.cpp | 32 --- ui/dialog_manage_routes.h | 2 +- ui/dialog_manage_routes.ui | 103 ---------- ui/dialog_vpn_settings.cpp | 45 ++++ ui/dialog_vpn_settings.h | 29 +++ ui/dialog_vpn_settings.ui | 194 ++++++++++++++++++ ui/mainwindow.cpp | 64 +++--- ui/mainwindow.h | 2 + ui/mainwindow.ui | 8 +- 24 files changed, 454 insertions(+), 190 deletions(-) create mode 100644 ui/dialog_vpn_settings.cpp create mode 100644 ui/dialog_vpn_settings.h create mode 100644 ui/dialog_vpn_settings.ui diff --git a/.gitignore b/.gitignore index a148a15..8b8ef4e 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,4 @@ CMakeLists.txt.user* # Deploy /deployment +/neko*.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index fcedb5e..d3c68af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/db/ConfigBuilder.cpp b/db/ConfigBuilder.cpp index 0d7a213..60c108a 100644 --- a/db/ConfigBuilder.cpp +++ b/db/ConfigBuilder.cpp @@ -1,9 +1,11 @@ #include "db/ConfigBuilder.hpp" #include "db/Database.hpp" #include "fmt/includes.h" +#include "fmt/Preset.hpp" #include #include +#include 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(); + } + } \ No newline at end of file diff --git a/db/ConfigBuilder.hpp b/db/ConfigBuilder.hpp index c844173..bdb811c 100644 --- a/db/ConfigBuilder.hpp +++ b/db/ConfigBuilder.hpp @@ -51,4 +51,8 @@ namespace NekoRay { QString BuildChainInternal(int chainId, const QList> &ents, const QSharedPointer &status); + + QString WriteVPNSingBoxConfig(); + + QString WriteVPNLinuxScript(const QString &protectPath, const QString &configPath); } diff --git a/examples/sing-box-vpn.json b/examples/sing-box-vpn.json index af6b0a0..0da0e9f 100644 --- a/examples/sing-box-vpn.json +++ b/examples/sing-box-vpn.json @@ -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% ] } } \ No newline at end of file diff --git a/fmt/AbstractBean.hpp b/fmt/AbstractBean.hpp index 24e6e09..6dbf60f 100644 --- a/fmt/AbstractBean.hpp +++ b/fmt/AbstractBean.hpp @@ -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(); diff --git a/fmt/Bean2External.cpp b/fmt/Bean2External.cpp index e7516e7..d943ee1 100644 --- a/fmt/Bean2External.cpp +++ b/fmt/Bean2External.cpp @@ -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; diff --git a/fmt/CustomBean.hpp b/fmt/CustomBean.hpp index 35451d2..ac11753 100644 --- a/fmt/CustomBean.hpp +++ b/fmt/CustomBean.hpp @@ -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; diff --git a/fmt/NaiveBean.hpp b/fmt/NaiveBean.hpp index 25a2642..f6b72c6 100644 --- a/fmt/NaiveBean.hpp +++ b/fmt/NaiveBean.hpp @@ -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; }; diff --git a/go/cmd/nekoray_core/protect_bindinterface_windows.go b/go/cmd/nekoray_core/protect_bindinterface_windows.go index 318c6b3..83ed48d 100644 --- a/go/cmd/nekoray_core/protect_bindinterface_windows.go +++ b/go/cmd/nekoray_core/protect_bindinterface_windows.go @@ -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 } diff --git a/main/GuiUtils.hpp b/main/GuiUtils.hpp index 2f913e4..166aea4 100644 --- a/main/GuiUtils.hpp +++ b/main/GuiUtils.hpp @@ -54,6 +54,7 @@ inline QMenu *CreateMenu(QWidget *parent, const QList &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; diff --git a/main/NekoRay.cpp b/main/NekoRay.cpp index 0945ebc..91b0372 100644 --- a/main/NekoRay.cpp +++ b/main/NekoRay.cpp @@ -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)); } diff --git a/main/NekoRay_DataStore.hpp b/main/NekoRay_DataStore.hpp index 854b11b..0ef33a0 100644 --- a/main/NekoRay_DataStore.hpp +++ b/main/NekoRay_DataStore.hpp @@ -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 = ""; diff --git a/main/NekoRay_Utils.hpp b/main/NekoRay_Utils.hpp index b1013b6..30b56d9 100644 --- a/main/NekoRay_Utils.hpp +++ b/main/NekoRay_Utils.hpp @@ -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(), diff --git a/translations/zh_CN.ts b/translations/zh_CN.ts index ba9fb08..8004b77 100644 --- a/translations/zh_CN.ts +++ b/translations/zh_CN.ts @@ -486,17 +486,32 @@ Custom (global) 自定义 (全局) + + + DialogVPNSettings + + VPN Settings + VPN 设置 + VPN Implementation VPN 实现 + + Hide Console + 隐藏控制台 + VPN Enable IPv6 启用 VPN IPv6 - Hide Console - 隐藏控制台 + Bypass CIDR + 绕过 CIDR + + + Bypass Process Name + 绕过进程名 @@ -819,10 +834,6 @@ Stop 停止 - - Routing VPN Settings - 路由 VPN 设置 - Add profile from clipboard 从剪切板添加 @@ -1029,10 +1040,6 @@ End: %2 QR Code and link 显示 QR Code 和分享链接 - - Export V2ray config - 导出 V2ray 配置 - Active Routing 当前路由规则 @@ -1141,6 +1148,14 @@ End: %2 Export %1 config 导出 %1 配置 + + Routing Settings + 路由设置 + + + VPN Settings + VPN 设置 + ProxyItem diff --git a/ui/dialog_manage_routes.cpp b/ui/dialog_manage_routes.cpp index 7806b68..15d15fc 100644 --- a/ui/dialog_manage_routes.cpp +++ b/ui/dialog_manage_routes.cpp @@ -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 @@ -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(); } diff --git a/ui/dialog_manage_routes.h b/ui/dialog_manage_routes.h index cb09531..4e2a993 100644 --- a/ui/dialog_manage_routes.h +++ b/ui/dialog_manage_routes.h @@ -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; diff --git a/ui/dialog_manage_routes.ui b/ui/dialog_manage_routes.ui index 4449dd6..7ce4394 100644 --- a/ui/dialog_manage_routes.ui +++ b/ui/dialog_manage_routes.ui @@ -111,106 +111,6 @@ - - - - - - - 0 - 0 - - - - VPN Implementation - - - - - - - - gVisor - - - - - System - - - - - - - - - 0 - 0 - - - - MTU - - - - - - - true - - - - 9000 - - - - - 1500 - - - - - - - - - 0 - 0 - - - - Hide Console - - - - - - - - 0 - 0 - - - - VPN Enable IPv6 - - - - - - - - 0 - 0 - - - - FakeDNS - - - - - @@ -470,9 +370,6 @@ sniffing_mode outbound_domain_strategy - vpn_implementation - vpn_mtu - fake_dns dns_remote dns_direct enhance_resolve_server_domain diff --git a/ui/dialog_vpn_settings.cpp b/ui/dialog_vpn_settings.cpp new file mode 100644 index 0000000..1f95eef --- /dev/null +++ b/ui/dialog_vpn_settings.cpp @@ -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(); +} diff --git a/ui/dialog_vpn_settings.h b/ui/dialog_vpn_settings.h new file mode 100644 index 0000000..91b5f3e --- /dev/null +++ b/ui/dialog_vpn_settings.h @@ -0,0 +1,29 @@ +#ifndef NEKORAY_DIALOG_VPN_SETTINGS_H +#define NEKORAY_DIALOG_VPN_SETTINGS_H + +#include + + +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 diff --git a/ui/dialog_vpn_settings.ui b/ui/dialog_vpn_settings.ui new file mode 100644 index 0000000..c657517 --- /dev/null +++ b/ui/dialog_vpn_settings.ui @@ -0,0 +1,194 @@ + + + DialogVPNSettings + + + + 0 + 0 + 600 + 600 + + + + VPN Settings + + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + VPN Implementation + + + + + + + + gVisor + + + + + System + + + + + + + + + 0 + 0 + + + + MTU + + + + + + + true + + + + 9000 + + + + + 1500 + + + + + + + + + + + + + + Hide Console + + + + + + + VPN Enable IPv6 + + + + + + + FakeDNS + + + + + + + + + + + + Bypass CIDR + + + + + + + + + + + + Bypass Process Name + + + + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + vpn_implementation + vpn_mtu + hide_console + vpn_ipv6 + fake_dns + vpn_bypass_cidr + vpn_bypass_process + + + + + buttonBox + accepted() + DialogVPNSettings + accept() + + + 399 + 575 + + + 399 + 299 + + + + + buttonBox + rejected() + DialogVPNSettings + reject() + + + 399 + 575 + + + 399 + 299 + + + + + diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index af53d6b..ab4a756 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -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([=] { diff --git a/ui/mainwindow.h b/ui/mainwindow.h index 3e24d3d..3a23092 100644 --- a/ui/mainwindow.h +++ b/ui/mainwindow.h @@ -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(); diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index 86a16d1..553e8ef 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -498,6 +498,7 @@ + @@ -590,7 +591,7 @@ - Routing VPN Settings + Routing Settings @@ -822,6 +823,11 @@ Resolve domain + + + VPN Settings + +