refactor vpn mode

This commit is contained in:
arm64v8a
2023-05-01 20:28:14 +09:00
parent 79ef90f3bf
commit 50387db15e
24 changed files with 391 additions and 382 deletions

View File

@@ -48,7 +48,7 @@ Returns the return value of the executed command
uint WinCommander::runProcessElevated(const QString &path,
const QStringList &parameters,
const QString &workingDir,
bool hide, bool aWait) {
int nShow, bool aWait) {
uint result = 0;
#ifdef Q_OS_WIN
@@ -79,7 +79,7 @@ uint WinCommander::runProcessElevated(const QString &path,
shex.lpParameters = pszParameters;
shex.lpDirectory = pszDirectory;
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
shex.nShow = hide ? SW_HIDE : SW_SHOWMINIMIZED;
shex.nShow = nShow;
ShellExecuteEx(&shex);
if (shex.hProcess)

View File

@@ -28,10 +28,14 @@
class WinCommander {
public:
static const int SW_HIDE = 0;
static const int SW_NORMAL = 1;
static const int SW_SHOWMINIMIZED = 2;
static uint runProcessElevated(const QString &path,
const QStringList &parameters = QStringList(),
const QString &workingDir = QString(),
bool hide = false, bool aWait = true);
int nShow = SW_SHOWMINIMIZED, bool aWait = true);
};
#endif // WINCOMMANDER_H

View File

@@ -40,6 +40,11 @@ QJsonObject JsonEditor::OpenEditor() {
auto string = jsonEditor->toPlainText();
while (resultCode == QDialog::Accepted && !VerifyJsonString(string).isEmpty()) {
if (string.isEmpty()) {
resultCode = QDialog::Accepted;
final = {};
break;
}
QvMessageBoxWarn(this, tr("Json Contains Syntax Errors"),
tr("You must correct these errors before continuing."));
resultCode = this->exec();

View File

@@ -13,6 +13,24 @@
namespace NekoRay {
QStringList getAutoBypassExternalProcessPaths(const QSharedPointer<BuildConfigResult> &result) {
QStringList paths;
for (const auto &ext: result->exts) {
auto path = ext.first.program;
if (path.trimmed().isEmpty()) continue;
paths << path.replace("\\", "/");
}
return paths;
}
QString genTunName() {
auto tun_name = "nekoray-tun";
#ifdef Q_OS_MACOS
tun_name = "utun9";
#endif
return tun_name;
}
void MergeJson(const QJsonObject &custom, QJsonObject &outbound) {
// 合并
if (custom.isEmpty()) return;
@@ -215,8 +233,8 @@ namespace NekoRay {
{"tag", "block"},
};
// DNS Routing
if (dataStore->dns_routing && !status->forTest) {
// DNS out
if (!status->forTest) {
QJsonObject dnsOut;
dnsOut["protocol"] = "dns";
dnsOut["tag"] = "dns-out";
@@ -300,7 +318,7 @@ namespace NekoRay {
// Routing
QJsonObject routing;
routing["domainStrategy"] = dataStore->domain_strategy;
routing["domainMatcher"] = dataStore->domain_matcher == DomainMatcher::MPH ? "mph" : "linear";
routing["domainMatcher"] = "mph";
if (status->forTest) routing["domainStrategy"] = "AsIs";
// final add user rule (block)
@@ -457,7 +475,12 @@ namespace NekoRay {
// chain rules: this
auto ext_mapping_port = 0;
auto ext_socks_port = 0;
auto thisExternalStat = ent->bean->NeedExternal(isFirstProfile, dataStore->running_spmode == SystemProxyMode::VPN);
auto thisExternalStat = ent->bean->NeedExternal(isFirstProfile);
if (thisExternalStat < 0) {
status->result->error = "This configuration cannot be set automatically, please try another.";
return {};
}
// determine port
if (thisExternalStat > 0) {
if (ent->type == "custom") {
@@ -658,9 +681,28 @@ namespace NekoRay {
},
};
}
// apply domain_strategy
inboundObj["domain_strategy"] = dataStore->outbound_domain_strategy;
//
inboundObj["domain_strategy"] = dataStore->domain_strategy;
status->inbounds += inboundObj;
}
// tun-in
if (IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn) {
QJsonObject inboundObj;
inboundObj["tag"] = "tun-in";
inboundObj["type"] = "tun";
inboundObj["interface_name"] = genTunName();
inboundObj["auto_route"] = true;
inboundObj["endpoint_independent_nat"] = true;
inboundObj["mtu"] = dataStore->vpn_mtu;
inboundObj["stack"] = Preset::SingBox::VpnImplementation.value(dataStore->vpn_implementation);
inboundObj["strict_route"] = dataStore->vpn_strict_route;
inboundObj["inet4_address"] = "172.19.0.1/28";
if (dataStore->vpn_ipv6) inboundObj["inet4_address"] = "fdfe:dcba:9876::1/126";
if (dataStore->sniffing_mode != SniffingMode::DISABLE) {
inboundObj["sniff"] = true;
inboundObj["sniff_override_destination"] = dataStore->sniffing_mode == SniffingMode::FOR_DESTINATION;
}
inboundObj["domain_strategy"] = dataStore->domain_strategy;
status->inbounds += inboundObj;
}
@@ -805,7 +847,12 @@ namespace NekoRay {
// Routing
// dns hijack
if (!status->forTest) status->routingRules += QJsonObject{{"protocol", "dns"}, {"outbound", "dns-out"}};
if (!status->forTest) {
status->routingRules += QJsonObject{
{"protocol", "dns"},
{"outbound", "dns-out"},
};
}
// sing-box routing rule object
auto add_rule_route = [&](const QStringList &list, bool isIP, const QString &out) {
@@ -823,6 +870,49 @@ namespace NekoRay {
add_rule_route(status->domainListRemote, false, tagProxy);
add_rule_route(status->domainListDirect, false, "bypass");
// built-in rules
status->routingRules += QJsonObject{
{"network", "udp"},
{"port", QJsonArray{135, 137, 138, 5353}},
{"outbound", "block"},
};
status->routingRules += QJsonObject{
{"ip_cidr", QJsonArray{"224.0.0.0/3", "ff00::/8"}},
{"outbound", "block"},
};
status->routingRules += QJsonObject{
{"source_ip_cidr", QJsonArray{"224.0.0.0/3", "ff00::/8"}},
{"outbound", "block"},
};
// tun user rule
if (IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn) {
auto match_out = NekoRay::dataStore->vpn_rule_white ? "proxy" : "bypass";
QString process_name_rule = dataStore->vpn_rule_process.trimmed();
if (!process_name_rule.isEmpty()) {
auto arr = SplitLinesSkipSharp(process_name_rule);
QJsonObject rule{{"outbound", match_out},
{"process_name", QList2QJsonArray(arr)}};
status->routingRules += rule;
}
QString cidr_rule = dataStore->vpn_rule_cidr.trimmed();
if (!cidr_rule.isEmpty()) {
auto arr = SplitLinesSkipSharp(cidr_rule);
QJsonObject rule{{"outbound", match_out},
{"ip_cidr", QList2QJsonArray(arr)}};
status->routingRules += rule;
}
auto autoBypassExternalProcessPaths = getAutoBypassExternalProcessPaths(status->result);
if (!autoBypassExternalProcessPaths.isEmpty()) {
QJsonObject rule{{"outbound", "bypass"},
{"process_name", QList2QJsonArray(autoBypassExternalProcessPaths)}};
status->routingRules += rule;
}
}
// geopath
auto geoip = FindCoreAsset("geoip.db");
auto geosite = FindCoreAsset("geosite.db");
@@ -836,7 +926,7 @@ namespace NekoRay {
QJSONARRAY_ADD(routingRules, status->routingRules)
auto routeObj = QJsonObject{
{"rules", routingRules},
{"auto_detect_interface", NekoRay::dataStore->core_box_auto_detect_interface},
{"auto_detect_interface", dataStore->spmode_vpn},
{
"geoip",
QJsonObject{
@@ -873,9 +963,10 @@ namespace NekoRay {
}
QString WriteVPNSingBoxConfig() {
// tun user rule
auto match_out = NekoRay::dataStore->vpn_rule_white ? "nekoray-socks" : "direct";
auto no_match_out = NekoRay::dataStore->vpn_rule_white ? "direct" : "nekoray-socks";
// user rule
QString process_name_rule = dataStore->vpn_rule_process.trimmed();
if (!process_name_rule.isEmpty()) {
auto arr = SplitLinesSkipSharp(process_name_rule);
@@ -883,6 +974,7 @@ namespace NekoRay {
{"process_name", QList2QJsonArray(arr)}};
process_name_rule = "," + QJsonObject2QString(rule, false);
}
QString cidr_rule = dataStore->vpn_rule_cidr.trimmed();
if (!cidr_rule.isEmpty()) {
auto arr = SplitLinesSkipSharp(cidr_rule);
@@ -890,11 +982,9 @@ namespace NekoRay {
{"ip_cidr", QList2QJsonArray(arr)}};
cidr_rule = "," + QJsonObject2QString(rule, false);
}
// tun name
auto tun_name = "nekoray-tun";
#ifdef Q_OS_MACOS
tun_name = "utun9";
#endif
// TODO bypass ext core process path?
// auth
QString socks_user_pass;
if (dataStore->inbound_auth->NeedAuth()) {
@@ -910,7 +1000,7 @@ namespace NekoRay {
.replace("%STACK%", Preset::SingBox::VpnImplementation.value(dataStore->vpn_implementation))
.replace("%PROCESS_NAME_RULE%", process_name_rule)
.replace("%CIDR_RULE%", cidr_rule)
.replace("%TUN_NAME%", tun_name)
.replace("%TUN_NAME%", genTunName())
.replace("%STRICT_ROUTE%", dataStore->vpn_strict_route ? "true" : "false")
.replace("%SOCKS_USER_PASS%", socks_user_pass)
.replace("%FINAL_OUT%", no_match_out)

View File

@@ -54,7 +54,7 @@ namespace NekoRay::fmt {
//
virtual int NeedExternal(bool isFirstProfile, bool isVPN) { return 0; };
virtual int NeedExternal(bool isFirstProfile) { return 0; };
virtual CoreObjOutboundBuildResult BuildCoreObjV2Ray() { return {}; };

View File

@@ -20,38 +20,50 @@
auto TempFile = QFileInfo(f).absoluteFilePath();
namespace NekoRay::fmt {
// -1: Cannot use this config
// 0: Internal
// 1: Mapping External
// 2: Direct External
int NaiveBean::NeedExternal(bool isFirstProfile, bool isVPN) {
if (isFirstProfile && !isVPN) {
int NaiveBean::NeedExternal(bool isFirstProfile) {
if (isFirstProfile) {
if (dataStore->spmode_vpn) {
return 1;
}
return 2;
}
return 1;
}
int HysteriaBean::NeedExternal(bool isFirstProfile, bool isVPN) {
int HysteriaBean::NeedExternal(bool isFirstProfile) {
auto hysteriaCore = [=] {
if (isFirstProfile) {
if (dataStore->spmode_vpn && protocol != hysteria_protocol_facktcp && hopPort.trimmed().isEmpty()) {
return 1;
}
return 2;
} else {
if (protocol == hysteria_protocol_facktcp || !hopPort.trimmed().isEmpty()) {
return -1;
}
}
return 1;
};
if (IS_NEKO_BOX) {
if (protocol == hysteria_protocol_udp && hopPort.trimmed().isEmpty()) {
// sing-box support
return 0;
} else {
// hysteria core support
if (isFirstProfile && !isVPN) {
return 2;
}
return 1;
return hysteriaCore();
}
} else {
if (isFirstProfile && !isVPN) {
return 2;
}
return 1;
return hysteriaCore();
}
}
int CustomBean::NeedExternal(bool isFirstProfile, bool isVPN) {
int CustomBean::NeedExternal(bool isFirstProfile) {
if (core == "internal" || core == "internal-full") return 0;
return 1;
}
@@ -99,8 +111,8 @@ namespace NekoRay::fmt {
// determine server format
auto is_direct = external_stat == 2;
auto sni2 = sni;
if (sni.isEmpty() && is_direct) sni2 = serverAddress;
auto sniGen = sni;
if (sni.isEmpty() && !IsIpAddress(serverAddress)) sniGen = serverAddress;
auto server = serverAddress;
if (!hopPort.trimmed().isEmpty()) {
@@ -130,7 +142,7 @@ namespace NekoRay::fmt {
if (protocol == hysteria_protocol_facktcp) config["protocol"] = "faketcp";
if (protocol == hysteria_protocol_wechat_video) config["protocol"] = "wechat-video";
if (!sni2.isEmpty()) config["server_name"] = sni2;
if (!sniGen.isEmpty()) config["server_name"] = sniGen;
if (!alpn.isEmpty()) config["alpn"] = alpn;
if (!caText.trimmed().isEmpty()) {

View File

@@ -31,7 +31,7 @@ namespace NekoRay::fmt {
return core;
};
QString DisplayCoreType() override { return NeedExternal(false, false) ? core : software_core_name; };
QString DisplayCoreType() override { return NeedExternal(false) ? core : software_core_name; };
QString DisplayAddress() override {
if (core == "internal") {
@@ -47,7 +47,7 @@ namespace NekoRay::fmt {
return AbstractBean::DisplayAddress();
};
int NeedExternal(bool isFirstProfile, bool isVPN) override;
int NeedExternal(bool isFirstProfile) override;
ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override;

View File

@@ -63,11 +63,11 @@ namespace NekoRay::fmt {
return ::DisplayAddress(serverAddress, serverPort);
}
QString DisplayCoreType() override { return NeedExternal(false, false) == 0 ? software_core_name : "Hysteria"; };
QString DisplayCoreType() override { return NeedExternal(false) == 0 ? software_core_name : "Hysteria"; };
QString DisplayType() override { return "Hysteria"; };
int NeedExternal(bool isFirstProfile, bool isVPN) override;
int NeedExternal(bool isFirstProfile) override;
ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override;

View File

@@ -27,7 +27,7 @@ namespace NekoRay::fmt {
QString DisplayType() override { return "Naive"; };
int NeedExternal(bool isFirstProfile, bool isVPN) override;
int NeedExternal(bool isFirstProfile) override;
ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override;

View File

@@ -17,9 +17,6 @@ func main() {
fmt.Println("sing-box-extra:", boxbox.Version(), "NekoBox:", neko_common.Version_neko)
fmt.Println()
// local DNS transport
_ = os.Setenv("GODEBUG", os.Getenv("GODEBUG")+",netdns=go")
// nekobox_core
if len(os.Args) > 1 && os.Args[1] == "nekobox" {
neko_common.RunMode = neko_common.RunMode_NekoBox_Core

View File

@@ -1,6 +1,6 @@
#!/bin/bash
sudo apt install fuse -y
sudo apt-get install fuse -y
cp -r linux64 nekoray.AppDir
@@ -25,7 +25,7 @@ chmod +x nekoray.AppDir/AppRun
# build
curl -L -O https://github.com/AppImage/AppImageKit/releases/latest/download/appimagetool-x86_64.AppImage
curl -fLSO https://github.com/AppImage/AppImageKit/releases/latest/download/appimagetool-x86_64.AppImage
chmod +x appimagetool-x86_64.AppImage
./appimagetool-x86_64.AppImage nekoray.AppDir

View File

@@ -16,14 +16,6 @@ namespace NekoRay {
};
}
namespace SystemProxyMode {
enum SystemProxyMode {
DISABLE,
SYSTEM_PROXY,
VPN,
};
}
namespace CoreType {
enum CoreType {
V2RAY,

View File

@@ -30,7 +30,6 @@ namespace NekoRay {
_add(new configItem("remote_dns_strategy", &remote_dns_strategy, itemType::string));
_add(new configItem("direct_dns", &direct_dns, itemType::string));
_add(new configItem("direct_dns_strategy", &direct_dns_strategy, itemType::string));
_add(new configItem("domain_matcher", &domain_matcher, itemType::integer));
_add(new configItem("domain_strategy", &domain_strategy, itemType::string));
_add(new configItem("outbound_domain_strategy", &outbound_domain_strategy, itemType::string));
_add(new configItem("sniffing_mode", &sniffing_mode, itemType::integer));
@@ -46,7 +45,7 @@ namespace NekoRay {
_add(new configItem("remember_id", &remember_id, itemType::integer));
_add(new configItem("remember_enable", &remember_enable, itemType::boolean));
_add(new configItem("language", &language, itemType::integer));
_add(new configItem("spmode", &remember_spmode, itemType::integer));
_add(new configItem("spmode2", &remember_spmode, itemType::stringList));
_add(new configItem("skip_cert", &skip_cert, itemType::boolean));
_add(new configItem("hk_mw", &hotkey_mainwindow, itemType::string));
_add(new configItem("hk_group", &hotkey_group, itemType::string));
@@ -74,14 +73,13 @@ namespace NekoRay {
_add(new configItem("max_log_line", &max_log_line, itemType::integer));
_add(new configItem("splitter_state", &splitter_state, itemType::string));
_add(new configItem("utlsFingerprint", &utlsFingerprint, itemType::string));
_add(new configItem("core_box_auto_detect_interface", &core_box_auto_detect_interface, itemType::boolean));
_add(new configItem("core_box_clash_api", &core_box_clash_api, itemType::integer));
_add(new configItem("core_box_clash_api_secret", &core_box_clash_api_secret, itemType::string));
_add(new configItem("core_box_underlying_dns", &core_box_underlying_dns, itemType::string));
_add(new configItem("core_ray_direct_dns", &core_ray_direct_dns, itemType::boolean));
#ifndef Q_OS_WIN
_add(new configItem("vpn_internal_tun", &vpn_internal_tun, itemType::boolean));
#ifdef Q_OS_WIN
_add(new configItem("core_ray_windows_disable_auto_interface", &core_ray_windows_disable_auto_interface, itemType::boolean));
_add(new configItem("vpn_already_admin", &vpn_already_admin, itemType::boolean));
#endif
}

View File

@@ -14,5 +14,6 @@ namespace NekoRay {
} // namespace NekoRay
#define IS_NEKO_BOX (NekoRay::coreType == NekoRay::CoreType::SING_BOX)
#define IS_NEKO_BOX_INTERNAL_TUN (IS_NEKO_BOX && NekoRay::dataStore->vpn_internal_tun)
#define ROUTES_PREFIX_NAME QString(IS_NEKO_BOX ? "routes_box" : "routes")
#define ROUTES_PREFIX QString(ROUTES_PREFIX_NAME + "/")

View File

@@ -54,7 +54,8 @@ namespace NekoRay {
int started_id = -1919;
bool core_running = false;
bool core_prepare_exit = false;
int running_spmode = NekoRay::SystemProxyMode::DISABLE;
bool spmode_vpn = false;
bool spmode_system_proxy = false;
bool need_keep_vpn_off = false;
QStringList ignoreConnTag = {};
@@ -104,7 +105,7 @@ namespace NekoRay {
QString utlsFingerprint = "";
// Remember
int remember_spmode = NekoRay::SystemProxyMode::DISABLE;
QStringList remember_spmode = {};
int remember_id = -1919;
bool remember_enable = false;
@@ -127,18 +128,17 @@ namespace NekoRay {
QString domain_strategy = "AsIs";
QString outbound_domain_strategy = "AsIs";
int sniffing_mode = SniffingMode::FOR_ROUTING;
int domain_matcher = DomainMatcher::MPH;
QString custom_route_global = "{\"rules\": []}";
QString active_routing = "Default";
// VPN
bool vpn_internal_tun = true;
int vpn_implementation = 0;
int vpn_mtu = 9000;
bool vpn_ipv6 = false;
bool vpn_hide_console = false;
bool vpn_strict_route = false;
bool vpn_rule_white = false;
bool vpn_already_admin = false; // not saved on Windows
QString vpn_rule_process = "";
QString vpn_rule_cidr = "";
@@ -149,7 +149,6 @@ namespace NekoRay {
QString hotkey_system_proxy_menu = "";
// Core
bool core_box_auto_detect_interface = true;
int core_box_clash_api = -9090;
QString core_box_clash_api_secret = "";
QString core_box_underlying_dns = "";

View File

@@ -91,19 +91,11 @@
<source>Use proxy when updating subscription</source>
<translation>استفاده از پروکسی زمانی که اشتراک را بروزرسانی می کنید</translation>
</message>
<message>
<source>Language</source>
<translation type="vanished">زبان</translation>
</message>
<message>
<source>Security</source>
<translatorcomment>امنیت security</translatorcomment>
<translation>امنیت</translation>
</message>
<message>
<source>Insecure hint</source>
<translation type="vanished">اشاره ناامن</translation>
</message>
<message>
<source>Statistics refresh rate</source>
<translation>نرخ تازه سازی آمار ترافیک</translation>
@@ -357,10 +349,6 @@ For NekoBox, this rewrites the underlying(localhost) DNS in VPN mode, normal mod
<source>Network Settings (%1)</source>
<translation>تنظیمات شبکه (1%)</translation>
</message>
<message>
<source>Security Settings</source>
<translation type="vanished">تنظیمات امنیت</translation>
</message>
<message>
<source>When enabled, V2Ray will not check the validity of the TLS certificate provided by the remote host (the security is equivalent to plaintext)</source>
<translation type="unfinished"></translation>
@@ -503,14 +491,6 @@ These settings can be changed later.</source>
<source>Disable</source>
<translation>غیرفعال کردن</translation>
</message>
<message>
<source>The sniffing result is used for routing</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>The sniffing result is used for destination</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Remote DNS</source>
<translation type="unfinished"></translation>
@@ -523,14 +503,6 @@ These settings can be changed later.</source>
<source>Enable DNS Routing</source>
<translation>فعال کردن مسیریابی DNS</translation>
</message>
<message>
<source>V2Ray Domain Strategy</source>
<translation>استراتژی دامنه</translation>
</message>
<message>
<source>Matcher</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Block</source>
<translation type="unfinished"></translation>
@@ -607,16 +579,28 @@ These settings can be changed later.</source>
<source>Default Outbound</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Query Strategy</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Inbound &amp; Outbound Domain Strategy</source>
<source>DNS Query Strategy</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Domain Strategy</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Server Address Strategy</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Sniff result for routing</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Sniff result for destination</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -682,11 +666,12 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</source>
<translation type="unfinished">لغو کردن</translation>
</message>
<message>
<source>Don&apos;t ask for privilege elevation</source>
<source>Internal Tun</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Already Admin</source>
<source>Add a tun inbound to the profile startup, instead of using two processes.
This needs to be run NekoBox with administrator privileges.</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -1336,14 +1321,6 @@ Split by line.</source>
<source>Clear</source>
<translation>پاک کردن</translation>
</message>
<message>
<source>End</source>
<translation type="vanished">پایان</translation>
</message>
<message>
<source>Active</source>
<translation type="vanished">فعال</translation>
</message>
<message>
<source>Start: %1
End: %2</source>
@@ -1373,10 +1350,6 @@ End: %2</source>
<source>Starting profile %1</source>
<translation>اغاز پروفایل %1</translation>
</message>
<message>
<source>Profile is insecure: %1</source>
<translation type="vanished">پروفایل ناامن می باشد: %1</translation>
</message>
<message>
<source>Stopping profile %1</source>
<translation>متوقف کردن پروفایل %1</translation>
@@ -1405,13 +1378,13 @@ End: %2</source>
<source>Restart nekoray to take effect.</source>
<translation type="unfinished">برای اعمال تغییرات nekoray را مجددا راه اندازی کنید.</translation>
</message>
<message>
<source>Please run NekoBox as admin</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ProxyItem</name>
<message>
<source>Remove</source>
<translation type="vanished">حذف کردن</translation>
</message>
<message>
<source>Confirmation</source>
<translation>تائیدیه</translation>

View File

@@ -95,10 +95,6 @@
<source>Security</source>
<translation></translation>
</message>
<message>
<source>Insecure hint</source>
<translation type="vanished"></translation>
</message>
<message>
<source>Statistics refresh rate</source>
<translation></translation>
@@ -494,11 +490,11 @@ These settings can be changed later.</source>
<translation></translation>
</message>
<message>
<source>The sniffing result is used for routing</source>
<source>Sniff result for routing</source>
<translation></translation>
</message>
<message>
<source>The sniffing result is used for destination</source>
<source>Sniff result for destination</source>
<translation></translation>
</message>
<message>
@@ -513,14 +509,6 @@ These settings can be changed later.</source>
<source>Enable DNS Routing</source>
<translation> DNS </translation>
</message>
<message>
<source>V2Ray Domain Strategy</source>
<translation></translation>
</message>
<message>
<source>Matcher</source>
<translation></translation>
</message>
<message>
<source>Block</source>
<translation></translation>
@@ -597,17 +585,21 @@ These settings can be changed later.</source>
<source>Default Outbound</source>
<translation></translation>
</message>
<message>
<source>Query Strategy</source>
<translation>DNS </translation>
</message>
<message>
<source>Remote</source>
<translation></translation>
</message>
<message>
<source>Inbound &amp; Outbound Domain Strategy</source>
<translation></translation>
<source>DNS Query Strategy</source>
<translation>DNS </translation>
</message>
<message>
<source>Domain Strategy</source>
<translation></translation>
</message>
<message>
<source>Server Address Strategy</source>
<translation></translation>
</message>
</context>
<context>
@@ -675,12 +667,14 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
<translation></translation>
</message>
<message>
<source>Don&apos;t ask for privilege elevation</source>
<translation></translation>
<source>Internal Tun</source>
<translation> Tun</translation>
</message>
<message>
<source>Already Admin</source>
<translation></translation>
<source>Add a tun inbound to the profile startup, instead of using two processes.
This needs to be run NekoBox with administrator privileges.</source>
<translation>tun inbound使
NekoBox</translation>
</message>
</context>
<context>
@@ -1189,10 +1183,6 @@ End: %2</source>
<source>Move %1 item(s)</source>
<translation> %1 </translation>
</message>
<message>
<source>Profile is insecure: %1</source>
<translation type="vanished">: %1</translation>
</message>
<message>
<source>Remove Unavailable</source>
<translation></translation>
@@ -1395,6 +1385,10 @@ Split by line.</source>
<source>Restart nekoray to take effect.</source>
<translation> nekoray </translation>
</message>
<message>
<source>Please run NekoBox as admin</source>
<translation> NekoBox</translation>
</message>
</context>
<context>
<name>ProxyItem</name>
@@ -1498,26 +1492,6 @@ Release note:
<source>Chain Proxy</source>
<translation></translation>
</message>
<message>
<source>The configuration (insecure) can be detected and identified, the transmission is fully visible to the censor and is not resistant to man-in-the-middle tampering with the content of the communication.</source>
<translation type="vanished"> () .</translation>
</message>
<message>
<source>This configuration (Shadowsocks streaming cipher) can be accurately proactively detected and decrypted by censors without requiring a password, and cannot be mitigated by turning on IV replay filters on the server side.
Learn more: https://github.com/net4people/bbs/issues/24</source>
<translation type="vanished"> (Shadowsocks ) , IV .
了解更多: https://github.com/net4people/bbs/issues/24</translation>
</message>
<message>
<source>This configuration (VMess MD5 authentication) has been deprecated by upstream because of its questionable resistance to tampering and concealment.
As of January 1, 2022, compatibility with MD5 authentication information will be disabled on the server side by default. Any client using MD5 authentication information will not be able to connect to a server with VMess MD5 authentication information disabled.</source>
<translation type="vanished"> (VMess MD5 ) , , .
2022 1 1 , MD5 . 使 MD5 VMess MD5 .</translation>
</message>
<message>
<source>Requesting subscription: %1</source>
<translation>: %1</translation>
@@ -1534,10 +1508,6 @@ As of January 1, 2022, compatibility with MD5 authentication information will be
<source>Change of %1:</source>
<translation>%1 :</translation>
</message>
<message>
<source>This profile is cleartext, don&apos;t use it if the server is not in your local network.</source>
<translation type="vanished">使</translation>
</message>
<message>
<source>Select</source>
<translation></translation>

View File

@@ -392,7 +392,6 @@ void DialogBasicSettings::on_core_settings_clicked() {
w->setLayout(layout);
//
auto line = -1;
QCheckBox *core_box_auto_detect_interface;
QCheckBox *core_box_enable_clash_api;
MyLineEdit *core_box_clash_api;
MyLineEdit *core_box_clash_api_secret;
@@ -412,12 +411,6 @@ void DialogBasicSettings::on_core_settings_clicked() {
layout->addWidget(core_box_underlying_dns, line, 1);
//
if (IS_NEKO_BOX) {
auto core_box_auto_detect_interface_l = new QLabel("auto_detect_interface");
core_box_auto_detect_interface = new QCheckBox;
core_box_auto_detect_interface->setChecked(NekoRay::dataStore->core_box_auto_detect_interface);
layout->addWidget(core_box_auto_detect_interface_l, ++line, 0);
layout->addWidget(core_box_auto_detect_interface, line, 1);
//
auto core_box_enable_clash_api_l = new QLabel("Enable Clash API");
core_box_enable_clash_api = new QCheckBox;
core_box_enable_clash_api->setChecked(NekoRay::dataStore->core_box_clash_api > 0);
@@ -460,7 +453,6 @@ void DialogBasicSettings::on_core_settings_clicked() {
connect(box, &QDialogButtonBox::accepted, w, [=] {
NekoRay::dataStore->core_box_underlying_dns = core_box_underlying_dns->text();
if (IS_NEKO_BOX) {
NekoRay::dataStore->core_box_auto_detect_interface = core_box_auto_detect_interface->isChecked();
NekoRay::dataStore->core_box_clash_api = core_box_clash_api->text().toInt() * (core_box_enable_clash_api->isChecked() ? 1 : -1);
NekoRay::dataStore->core_box_clash_api_secret = core_box_clash_api_secret->text();
} else {

View File

@@ -31,16 +31,15 @@ DialogManageRoutes::DialogManageRoutes(QWidget *parent) : QDialog(parent), ui(ne
title_base = windowTitle();
if (IS_NEKO_BOX) {
ui->domain_v2ray->setVisible(false);
ui->outbound_domain_strategy->addItems(Preset::SingBox::DomainStrategy);
ui->domainStrategyCombo->addItems(Preset::SingBox::DomainStrategy);
} else {
ui->domain_v2ray->setVisible(true);
ui->outbound_domain_strategy->addItems({"AsIs", "UseIPv4", "UseIPv6", "PreferIPv4", "PreferIPv6"});
ui->domainStrategyCombo->addItems({"AsIs", "IPIfNonMatch", "IPOnDemand"});
}
//
ui->sniffing_mode->setCurrentIndex(NekoRay::dataStore->sniffing_mode);
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->dns_routing->setChecked(NekoRay::dataStore->dns_routing);
ui->dns_remote->setText(NekoRay::dataStore->remote_dns);
@@ -88,7 +87,6 @@ DialogManageRoutes::~DialogManageRoutes() {
void DialogManageRoutes::accept() {
NekoRay::dataStore->sniffing_mode = ui->sniffing_mode->currentIndex();
NekoRay::dataStore->domain_matcher = ui->domainMatcherCombo->currentIndex();
NekoRay::dataStore->domain_strategy = ui->domainStrategyCombo->currentText();
NekoRay::dataStore->outbound_domain_strategy = ui->outbound_domain_strategy->currentText();
NekoRay::dataStore->dns_routing = ui->dns_routing->isChecked();

View File

@@ -21,12 +21,6 @@
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Sniffing Mode</string>
</property>
@@ -41,33 +35,38 @@
</item>
<item>
<property name="text">
<string>The sniffing result is used for routing</string>
<string>Sniff result for routing</string>
</property>
</item>
<item>
<property name="text">
<string>The sniffing result is used for destination</string>
<string>Sniff result for destination</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
<widget class="QLabel" name="label_6">
<property name="toolTip">
<string notr="true">For V2Ray, it sets routing.domainStrategy
For sing-box, it sets inbound.domain_strategy</string>
</property>
<property name="text">
<string>Domain Strategy</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="domainStrategyCombo">
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Inbound &amp; Outbound Domain Strategy</string>
<string>Server Address Strategy</string>
</property>
</widget>
</item>
@@ -111,12 +110,6 @@
</item>
<item>
<widget class="QCheckBox" name="dns_routing">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Enable DNS Routing</string>
</property>
@@ -124,81 +117,19 @@
</item>
<item>
<widget class="QPushButton" name="queryStrategy">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Query Strategy</string>
<string>DNS Query Strategy</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QWidget" name="domain_v2ray" native="true">
<layout class="QHBoxLayout" name="_2" stretch="0,1,0,1">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>V2Ray Domain Strategy</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="domainStrategyCombo">
<property name="editable">
<bool>false</bool>
</property>
<item>
<property name="text">
<string notr="true">AsIs</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">IPIfNonMatch</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">IPOnDemand</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Matcher</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="domainMatcherCombo">
<item>
<property name="text">
<string notr="true">Original</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Minimal Perfect Hash Matcher</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
@@ -461,13 +392,8 @@
</widget>
<tabstops>
<tabstop>sniffing_mode</tabstop>
<tabstop>outbound_domain_strategy</tabstop>
<tabstop>dns_remote</tabstop>
<tabstop>dns_direct</tabstop>
<tabstop>dns_routing</tabstop>
<tabstop>queryStrategy</tabstop>
<tabstop>domainStrategyCombo</tabstop>
<tabstop>domainMatcherCombo</tabstop>
<tabstop>preset</tabstop>
<tabstop>custom_route_edit</tabstop>
<tabstop>def_outbound</tabstop>

View File

@@ -18,13 +18,12 @@ DialogVPNSettings::DialogVPNSettings(QWidget *parent) : QDialog(parent), ui(new
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_console);
ui->vpn_already_admin->setChecked(NekoRay::dataStore->vpn_already_admin);
#ifdef Q_OS_WIN
ui->vpn_already_admin->setVisible(false);
#else
#ifndef Q_OS_WIN
ui->hide_console->setVisible(false);
#endif
ui->strict_route->setChecked(NekoRay::dataStore->vpn_strict_route);
ui->single_core->setVisible(IS_NEKO_BOX);
ui->single_core->setChecked(NekoRay::dataStore->vpn_internal_tun);
//
D_LOAD_STRING(vpn_rule_cidr)
D_LOAD_STRING(vpn_rule_process)
@@ -56,7 +55,7 @@ void DialogVPNSettings::accept() {
NekoRay::dataStore->vpn_hide_console = ui->hide_console->isChecked();
NekoRay::dataStore->vpn_strict_route = ui->strict_route->isChecked();
NekoRay::dataStore->vpn_rule_white = ui->whitelist_mode->isChecked();
NekoRay::dataStore->vpn_already_admin = ui->vpn_already_admin->isChecked();
NekoRay::dataStore->vpn_internal_tun = ui->single_core->isChecked();
//
D_SAVE_STRING_QTEXTEDIT(vpn_rule_cidr)
D_SAVE_STRING_QTEXTEDIT(vpn_rule_process)

View File

@@ -86,13 +86,6 @@
<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">
@@ -100,13 +93,6 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="fake_dns">
<property name="text">
<string notr="true">FakeDNS</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="strict_route">
<property name="text">
@@ -115,12 +101,34 @@
</widget>
</item>
<item>
<widget class="QCheckBox" name="vpn_already_admin">
<widget class="QCheckBox" name="fake_dns">
<property name="text">
<string notr="true">FakeDNS</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="hide_console">
<property name="text">
<string>Hide Console</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="single_core">
<property name="toolTip">
<string>Don't ask for privilege elevation</string>
<string>Add a tun inbound to the profile startup, instead of using two processes.
This needs to be run NekoBox with administrator privileges.</string>
</property>
<property name="text">
<string>Already Admin</string>
<string>Internal Tun</string>
</property>
</widget>
</item>
@@ -198,6 +206,19 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>vpn_implementation</tabstop>
<tabstop>vpn_mtu</tabstop>
<tabstop>vpn_ipv6</tabstop>
<tabstop>strict_route</tabstop>
<tabstop>fake_dns</tabstop>
<tabstop>hide_console</tabstop>
<tabstop>single_core</tabstop>
<tabstop>vpn_rule_cidr</tabstop>
<tabstop>vpn_rule_process</tabstop>
<tabstop>whitelist_mode</tabstop>
<tabstop>troubleshooting</tabstop>
</tabstops>
<resources/>
<connections>
<connection>

View File

@@ -94,12 +94,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
software_name = "NekoBox";
software_core_name = "sing-box";
// replace default values
if (NekoRay::dataStore->log_level == "warning") {
NekoRay::dataStore->log_level = "info";
}
if (!Preset::SingBox::DomainStrategy.contains(NekoRay::dataStore->outbound_domain_strategy)) {
NekoRay::dataStore->outbound_domain_strategy = "";
}
if (NekoRay::dataStore->log_level == "warning") NekoRay::dataStore->log_level = "info";
if (!Preset::SingBox::DomainStrategy.contains(NekoRay::dataStore->domain_strategy)) NekoRay::dataStore->domain_strategy = "";
if (!Preset::SingBox::DomainStrategy.contains(NekoRay::dataStore->outbound_domain_strategy)) NekoRay::dataStore->outbound_domain_strategy = "";
//
if (QDir("dashboard").isEmpty()) {
QDir().mkdir("dashboard");
@@ -334,20 +331,19 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
MW_dialog_message("", "UpdateDataStore");
});
//
connect(ui->checkBox_VPN, &QCheckBox::clicked, this, [=](bool checked) {
neko_set_spmode(checked ? NekoRay::SystemProxyMode::VPN : NekoRay::SystemProxyMode::DISABLE);
});
connect(ui->checkBox_SystemProxy, &QCheckBox::clicked, this, [=](bool checked) {
neko_set_spmode(checked ? NekoRay::SystemProxyMode::SYSTEM_PROXY : NekoRay::SystemProxyMode::DISABLE);
});
connect(ui->checkBox_VPN, &QCheckBox::clicked, this, [=](bool checked) { neko_set_spmode_vpn(checked); });
connect(ui->checkBox_SystemProxy, &QCheckBox::clicked, this, [=](bool checked) { neko_set_spmode_system_proxy(checked); });
connect(ui->menu_spmode, &QMenu::aboutToShow, this, [=]() {
ui->menu_spmode_disabled->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::DISABLE);
ui->menu_spmode_system_proxy->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY);
ui->menu_spmode_vpn->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN);
ui->menu_spmode_disabled->setChecked(!(NekoRay::dataStore->spmode_system_proxy || NekoRay::dataStore->spmode_vpn));
ui->menu_spmode_system_proxy->setChecked(NekoRay::dataStore->spmode_system_proxy);
ui->menu_spmode_vpn->setChecked(NekoRay::dataStore->spmode_vpn);
});
connect(ui->menu_spmode_system_proxy, &QAction::triggered, this, [=](bool checked) { neko_set_spmode_system_proxy(checked); });
connect(ui->menu_spmode_vpn, &QAction::triggered, this, [=](bool checked) { neko_set_spmode_vpn(checked); });
connect(ui->menu_spmode_disabled, &QAction::triggered, this, [=]() {
neko_set_spmode_system_proxy(false);
neko_set_spmode_vpn(false);
});
connect(ui->menu_spmode_system_proxy, &QAction::triggered, this, [=]() { neko_set_spmode(NekoRay::SystemProxyMode::SYSTEM_PROXY); });
connect(ui->menu_spmode_vpn, &QAction::triggered, this, [=]() { neko_set_spmode(NekoRay::SystemProxyMode::VPN); });
connect(ui->menu_spmode_disabled, &QAction::triggered, this, [=]() { neko_set_spmode(NekoRay::SystemProxyMode::DISABLE); });
connect(ui->menu_qr, &QAction::triggered, this, [=]() { display_qr_link(false); });
connect(ui->menu_tcp_ping, &QAction::triggered, this, [=]() { speedtest_current_group(0); });
connect(ui->menu_url_test, &QAction::triggered, this, [=]() { speedtest_current_group(1); });
@@ -417,8 +413,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
// Start last
if (NekoRay::dataStore->remember_enable) {
if (NekoRay::dataStore->remember_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
neko_set_spmode(NekoRay::dataStore->remember_spmode, false);
if (NekoRay::dataStore->remember_spmode.contains("system_proxy")) {
neko_set_spmode_system_proxy(true, false);
}
if (NekoRay::dataStore->remember_spmode.contains("vpn")) {
neko_set_spmode_vpn(true, false);
}
if (NekoRay::dataStore->remember_id >= 0) {
runOnUiThread([=] { neko_start(NekoRay::dataStore->remember_id); });
@@ -514,7 +513,7 @@ void MainWindow::dialog_message_impl(const QString &sender, const QString &info)
auto changed = NekoRay::dataStore->Save();
if (info.contains("RouteChanged")) changed = true;
refresh_proxy_list();
if (info.contains("VPNChanged") && NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) {
if (info.contains("VPNChanged") && NekoRay::dataStore->spmode_vpn) {
MessageBoxWarning(tr("VPN settings changed"), tr("Restart VPN to take effect."));
} else if (changed && NekoRay::dataStore->started_id >= 0 &&
QMessageBox::question(GetMessageBoxParent(), tr("Confirmation"), tr("Settings changed, restart proxy?")) == QMessageBox::StandardButton::Yes) {
@@ -624,8 +623,9 @@ void MainWindow::on_commitDataRequest() {
}
void MainWindow::on_menu_exit_triggered() {
neko_set_spmode(NekoRay::SystemProxyMode::DISABLE, false);
if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) return;
neko_set_spmode_system_proxy(false, false);
neko_set_spmode_vpn(false, false);
if (NekoRay::dataStore->spmode_vpn) return;
RegisterHotkey(true);
//
on_commitDataRequest();
@@ -638,13 +638,21 @@ void MainWindow::on_menu_exit_triggered() {
if (exit_reason == 1) {
QDir::setCurrent(QApplication::applicationDirPath());
QProcess::startDetached("./updater", QStringList{});
} else if (exit_reason == 2) {
} else if (exit_reason == 2 || exit_reason == 3) {
QDir::setCurrent(QApplication::applicationDirPath());
auto arguments = NekoRay::dataStore->argv;
if (arguments.length() > 0) arguments.removeFirst();
auto isLauncher = qEnvironmentVariable("NKR_FROM_LAUNCHER") == "1";
if (isLauncher) arguments.prepend("--");
QProcess::startDetached(isLauncher ? "./launcher" : QApplication::applicationFilePath(), arguments);
auto program = isLauncher ? "./launcher" : QApplication::applicationFilePath();
if (exit_reason == 3) { // restart as admin
#ifdef Q_OS_WIN
WinCommander::runProcessElevated(program, arguments, "", WinCommander::SW_NORMAL, false);
#endif
} else {
QProcess::startDetached(program, arguments);
}
}
tray->hide();
QCoreApplication::quit();
@@ -654,23 +662,11 @@ void MainWindow::on_menu_exit_triggered() {
refresh_status(); \
return;
void MainWindow::neko_set_spmode(int mode, bool save) {
if (mode != NekoRay::dataStore->running_spmode) {
// DISABLE
if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
ClearSystemProxy();
} else if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) {
if (!StopVPNProcess()) {
neko_set_spmode_FAILED
}
}
// ENABLE
if (mode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
void MainWindow::neko_set_spmode_system_proxy(bool enable, bool save) {
if (enable != NekoRay::dataStore->spmode_system_proxy) {
if (enable) {
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
if (mode == NekoRay::SystemProxyMode::SYSTEM_PROXY && !IS_NEKO_BOX && !IsValidPort(NekoRay::dataStore->inbound_http_port)) {
if (!IS_NEKO_BOX && !IsValidPort(NekoRay::dataStore->inbound_http_port)) {
auto btn = QMessageBox::warning(this, software_name,
tr("Http inbound is not enabled, can't set system proxy."),
"OK", tr("Settings"), "", 0, 0);
@@ -682,29 +678,72 @@ void MainWindow::neko_set_spmode(int mode, bool save) {
#endif
auto socks_port = NekoRay::dataStore->inbound_socks_port;
auto http_port = NekoRay::dataStore->inbound_http_port;
if (IS_NEKO_BOX) {
http_port = socks_port;
}
if (IS_NEKO_BOX) http_port = socks_port;
SetSystemProxy(http_port, socks_port);
} else if (mode == NekoRay::SystemProxyMode::VPN) {
if (NekoRay::dataStore->need_keep_vpn_off) {
MessageBoxWarning(software_name,
tr("Current server is incompatible with VPN. Please stop the server first, enable VPN mode, and then restart."));
neko_set_spmode_FAILED
} else {
ClearSystemProxy();
}
}
if (save) {
NekoRay::dataStore->remember_spmode.removeAll("system_proxy");
if (enable) {
NekoRay::dataStore->remember_spmode.append("system_proxy");
}
NekoRay::dataStore->Save();
}
NekoRay::dataStore->spmode_system_proxy = enable;
refresh_status();
}
void MainWindow::neko_set_spmode_vpn(bool enable, bool save) {
if (enable != NekoRay::dataStore->spmode_vpn) {
if (enable) {
if (IS_NEKO_BOX_INTERNAL_TUN) {
#ifdef Q_OS_WIN
if (!Windows_IsInAdmin()) {
auto n = QMessageBox::warning(GetMessageBoxParent(), software_name, tr("Please run NekoBox as admin"), QMessageBox::Yes | QMessageBox::No);
if (n == QMessageBox::Yes) {
this->exit_reason = 3;
on_menu_exit_triggered();
}
neko_set_spmode_FAILED
}
#endif
// TODO check permission for Linux
} else {
if (NekoRay::dataStore->need_keep_vpn_off) {
MessageBoxWarning(software_name, tr("Current server is incompatible with VPN. Please stop the server first, enable VPN mode, and then restart."));
neko_set_spmode_FAILED
}
if (!StartVPNProcess()) {
neko_set_spmode_FAILED
}
}
if (!StartVPNProcess()) {
neko_set_spmode_FAILED
} else {
if (IS_NEKO_BOX_INTERNAL_TUN) {
// current core is sing-box
} else {
if (!StopVPNProcess()) {
neko_set_spmode_FAILED
}
}
}
}
if (save) {
NekoRay::dataStore->remember_spmode = mode;
NekoRay::dataStore->remember_spmode.removeAll("vpn");
if (enable) {
NekoRay::dataStore->remember_spmode.append("vpn");
}
NekoRay::dataStore->Save();
}
NekoRay::dataStore->running_spmode = mode;
NekoRay::dataStore->spmode_vpn = enable;
refresh_status();
if (NekoRay::dataStore->started_id >= 0) neko_start(NekoRay::dataStore->started_id);
}
void MainWindow::refresh_status(const QString &traffic_update) {
@@ -736,8 +775,8 @@ void MainWindow::refresh_status(const QString &traffic_update) {
if (IS_NEKO_BOX) inbound_txt = QString("Mixed: %1").arg(display_socks);
ui->label_inbound->setText(inbound_txt);
//
ui->checkBox_VPN->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN);
ui->checkBox_SystemProxy->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY);
ui->checkBox_VPN->setChecked(NekoRay::dataStore->spmode_vpn);
ui->checkBox_SystemProxy->setChecked(NekoRay::dataStore->spmode_system_proxy);
if (select_mode) ui->label_running->setText("[" + tr("Select") + "]");
auto make_title = [=](bool isTray) {
@@ -747,11 +786,8 @@ void MainWindow::refresh_status(const QString &traffic_update) {
#endif
if (select_mode) tt << "[" + tr("Select") + "]";
if (!title_error.isEmpty()) tt << "[" + title_error + "]";
if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
tt << "[" + tr("System Proxy") + "]";
} else if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) {
tt << "[" + tr("VPN Mode") + "]";
}
if (NekoRay::dataStore->spmode_vpn) tt << "[VPN]";
if (NekoRay::dataStore->spmode_system_proxy) tt << "[" + tr("System Proxy") + "]";
tt << software_name;
if (!isTray) tt << "(" + QString(NKR_VERSION) + ")";
if (!NekoRay::dataStore->active_routing.isEmpty() && NekoRay::dataStore->active_routing != "Default") {
@@ -762,12 +798,15 @@ void MainWindow::refresh_status(const QString &traffic_update) {
};
auto icon_status_new = Icon::NONE;
if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
icon_status_new = Icon::SYSTEM_PROXY;
} else if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) {
icon_status_new = Icon::VPN;
} else if (!running.isNull()) {
icon_status_new = Icon::RUNNING;
if (!running.isNull()) {
if (NekoRay::dataStore->spmode_vpn) {
icon_status_new = Icon::VPN;
} else if (NekoRay::dataStore->spmode_system_proxy) {
icon_status_new = Icon::SYSTEM_PROXY;
} else {
icon_status_new = Icon::RUNNING;
}
}
// refresh title & window icon
@@ -1677,11 +1716,10 @@ bool MainWindow::StartVPNProcess() {
runOnNewThread([=] {
vpn_pid = 1; // TODO get pid?
WinCommander::runProcessElevated(QApplication::applicationDirPath() + "/nekobox_core.exe",
{"--disable-color", "run", "-c", configPath},
"",
NekoRay::dataStore->vpn_hide_console); // blocking
{"--disable-color", "run", "-c", configPath}, "",
NekoRay::dataStore->vpn_hide_console ? WinCommander::SW_HIDE : WinCommander::SW_SHOWMINIMIZED); // blocking
vpn_pid = 0;
runOnUiThread([=] { neko_set_spmode(NekoRay::SystemProxyMode::DISABLE); });
runOnUiThread([=] { neko_set_spmode_vpn(false); });
});
#else
QFile::remove(protectPath);
@@ -1695,7 +1733,7 @@ bool MainWindow::StartVPNProcess() {
if (state == QProcess::NotRunning) {
vpn_pid = 0;
vpn_process->deleteLater();
GetMainWindow()->neko_set_spmode(NekoRay::SystemProxyMode::DISABLE);
GetMainWindow()->neko_set_spmode_vpn(false);
}
});
//
@@ -1704,11 +1742,7 @@ bool MainWindow::StartVPNProcess() {
vpn_process->start("osascript", {"-e", QString("do shell script \"%1\" with administrator privileges")
.arg("bash " + scriptPath)});
#else
if (NekoRay::dataStore->vpn_already_admin) {
vpn_process->start("bash", {scriptPath});
} else {
vpn_process->start("pkexec", {"bash", scriptPath});
}
vpn_process->start("pkexec", {"bash", scriptPath});
#endif
vpn_process->waitForStarted();
vpn_pid = vpn_process->processId(); // actually it's pkexec or bash PID
@@ -1731,14 +1765,10 @@ bool MainWindow::StopVPNProcess(bool unconditional) {
p.start("osascript", {"-e", QString("do shell script \"%1\" with administrator privileges")
.arg("pkill -2 -U 0 nekobox_core")});
#else
if (NekoRay::dataStore->vpn_already_admin) {
p.start("bash", {"kill", "-2", Int2String(vpn_pid)});
if (unconditional) {
p.start("pkexec", {"killall", "-2", "nekobox_core"});
} else {
if (unconditional) {
p.start("pkexec", {"killall", "-2", "nekobox_core"});
} else {
p.start("pkexec", {"pkill", "-2", "-P", Int2String(vpn_pid)});
}
p.start("pkexec", {"pkill", "-2", "-P", Int2String(vpn_pid)});
}
#endif
p.waitForFinished();

View File

@@ -51,7 +51,9 @@ public:
void neko_stop(bool crash = false);
void neko_set_spmode(int mode, bool save = true);
void neko_set_spmode_system_proxy(bool enable, bool save = true);
void neko_set_spmode_vpn(bool enable, bool save = true);
void show_log_impl(const QString &log);