v2ray format migration

This commit is contained in:
armv9
2024-07-03 16:55:14 +09:00
parent df141f9079
commit cd9bb8f72d
32 changed files with 160 additions and 956 deletions

View File

@@ -150,7 +150,6 @@ set(PROJECT_SOURCES
db/ConfigBuilder.cpp
fmt/AbstractBean.cpp
fmt/Bean2CoreObj_ray.cpp
fmt/Bean2CoreObj_box.cpp
fmt/Bean2External.cpp
fmt/Bean2Link.cpp

View File

@@ -64,11 +64,7 @@ namespace NekoGui {
if (customBean != nullptr && customBean->core == "internal-full") {
result->coreConfig = QString2QJsonObject(customBean->config_simple);
} else {
if (IS_NEKO_BOX) {
BuildConfigSingBox(status);
} else {
BuildConfigV2Ray(status);
}
BuildConfigSingBox(status);
}
// apply custom config
@@ -157,254 +153,6 @@ namespace NekoGui {
status->ipListDirect += line; \
}
// V2Ray
void BuildConfigV2Ray(const std::shared_ptr<BuildConfigStatus> &status) {
// Log
auto logObj = QJsonObject{{"loglevel", dataStore->log_level}};
status->result->coreConfig.insert("log", logObj);
// Inbounds
QJsonObject sniffing{
{"destOverride", QJsonArray{"http", "tls", "quic"}},
{"enabled", true},
{"metadataOnly", false},
{"routeOnly", dataStore->routing->sniffing_mode == SniffingMode::FOR_ROUTING},
};
// socks-in
if (IsValidPort(dataStore->inbound_socks_port) && !status->forTest) {
QJsonObject inboundObj;
inboundObj["tag"] = "socks-in";
inboundObj["protocol"] = "socks";
inboundObj["listen"] = dataStore->inbound_address;
inboundObj["port"] = dataStore->inbound_socks_port;
QJsonObject socksSettings = {{"udp", true}};
if (dataStore->routing->sniffing_mode != SniffingMode::DISABLE) {
inboundObj["sniffing"] = sniffing;
}
if (dataStore->inbound_auth->NeedAuth()) {
socksSettings["auth"] = "password";
socksSettings["accounts"] = QJsonArray{
QJsonObject{
{"user", dataStore->inbound_auth->username},
{"pass", dataStore->inbound_auth->password},
},
};
}
inboundObj["settings"] = socksSettings;
status->inbounds += inboundObj;
}
// http-in
if (IsValidPort(dataStore->inbound_http_port) && !status->forTest) {
QJsonObject inboundObj;
inboundObj["tag"] = "http-in";
inboundObj["protocol"] = "http";
inboundObj["listen"] = dataStore->inbound_address;
inboundObj["port"] = dataStore->inbound_http_port;
if (dataStore->routing->sniffing_mode != SniffingMode::DISABLE) {
inboundObj["sniffing"] = sniffing;
}
if (dataStore->inbound_auth->NeedAuth()) {
inboundObj["settings"] = QJsonObject{
{"accounts", QJsonArray{
QJsonObject{
{"user", dataStore->inbound_auth->username},
{"pass", dataStore->inbound_auth->password},
},
}},
};
}
status->inbounds += inboundObj;
}
// Outbounds
auto tagProxy = BuildChain(0, status);
if (!status->result->error.isEmpty()) return;
// direct & bypass & block
status->outbounds += QJsonObject{
{"protocol", "freedom"},
{"domainStrategy", dataStore->core_ray_freedom_domainStrategy},
{"tag", "direct"},
};
status->outbounds += QJsonObject{
{"protocol", "freedom"},
{"domainStrategy", dataStore->core_ray_freedom_domainStrategy},
{"tag", "bypass"},
};
status->outbounds += QJsonObject{
{"protocol", "blackhole"},
{"tag", "block"},
};
// DNS out
if (!status->forTest) {
QJsonObject dnsOut;
dnsOut["protocol"] = "dns";
dnsOut["tag"] = "dns-out";
QJsonObject dnsOut_settings;
dnsOut_settings["network"] = "tcp";
dnsOut_settings["port"] = 53;
dnsOut_settings["address"] = "8.8.8.8";
dnsOut_settings["userLevel"] = 1;
dnsOut["settings"] = dnsOut_settings;
dnsOut["proxySettings"] = QJsonObject{{"tag", tagProxy},
{"transportLayer", true}};
status->outbounds += dnsOut;
status->routingRules += QJsonObject{
{"type", "field"},
{"port", "53"},
{"inboundTag", QJsonArray{"socks-in", "http-in"}},
{"outboundTag", "dns-out"},
};
}
// custom inbound
if (!status->forTest) QJSONARRAY_ADD(status->inbounds, QString2QJsonObject(dataStore->custom_inbound)["inbounds"].toArray())
status->result->coreConfig.insert("inbounds", status->inbounds);
status->result->coreConfig.insert("outbounds", status->outbounds);
// user rule
if (!status->forTest) {
DOMAIN_USER_RULE
IP_USER_RULE
}
// final add DNS
QJsonObject dns;
QJsonArray dnsServers;
// Remote or FakeDNS
QJsonObject dnsServerRemote;
dnsServerRemote["address"] = dataStore->routing->remote_dns;
dnsServerRemote["domains"] = QList2QJsonArray<QString>(status->domainListDNSRemote);
dnsServerRemote["queryStrategy"] = dataStore->routing->remote_dns_strategy;
if (!status->forTest) dnsServers += dnsServerRemote;
// Direct
auto directDnsAddress = dataStore->routing->direct_dns;
if (directDnsAddress.contains("://")) {
auto directDnsIp = SubStrBefore(SubStrAfter(directDnsAddress, "://"), "/");
if (IsIpAddress(directDnsIp)) {
status->routingRules.push_front(QJsonObject{
{"type", "field"},
{"ip", QJsonArray{directDnsIp}},
{"outboundTag", "direct"},
});
} else {
status->routingRules.push_front(QJsonObject{
{"type", "field"},
{"domain", QJsonArray{directDnsIp}},
{"outboundTag", "direct"},
});
}
} else if (directDnsAddress != "localhost") {
status->routingRules.push_front(QJsonObject{
{"type", "field"},
{"ip", QJsonArray{directDnsAddress}},
{"outboundTag", "direct"},
});
}
QJsonObject directObj{
{"address", directDnsAddress.replace("https://", "https+local://")},
{"queryStrategy", dataStore->routing->direct_dns_strategy},
{"domains", QList2QJsonArray<QString>(status->domainListDNSDirect)},
};
if (dataStore->routing->dns_final_out == "bypass") {
dnsServers.prepend(directObj);
} else {
dnsServers.append(directObj);
}
dns["disableFallback"] = true;
dns["servers"] = dnsServers;
dns["tag"] = "dns";
if (dataStore->routing->use_dns_object) {
dns = QString2QJsonObject(dataStore->routing->dns_object);
}
status->result->coreConfig.insert("dns", dns);
// Routing
QJsonObject routing;
routing["domainStrategy"] = dataStore->routing->domain_strategy;
if (status->forTest) routing["domainStrategy"] = "AsIs";
// final add user rule (block)
QJsonObject routingRule_tmp;
routingRule_tmp["type"] = "field";
routingRule_tmp["outboundTag"] = "block";
if (!status->ipListBlock.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["ip"] = QList2QJsonArray<QString>(status->ipListBlock);
status->routingRules += tmp;
}
if (!status->domainListBlock.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["domain"] = QList2QJsonArray<QString>(status->domainListBlock);
status->routingRules += tmp;
}
// final add user rule (proxy)
routingRule_tmp["outboundTag"] = "proxy";
if (!status->ipListRemote.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["ip"] = QList2QJsonArray<QString>(status->ipListRemote);
status->routingRules += tmp;
}
if (!status->domainListRemote.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["domain"] = QList2QJsonArray<QString>(status->domainListRemote);
status->routingRules += tmp;
}
// final add user rule (bypass)
routingRule_tmp["outboundTag"] = "bypass";
if (!status->ipListDirect.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["ip"] = QList2QJsonArray<QString>(status->ipListDirect);
status->routingRules += tmp;
}
if (!status->domainListDirect.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["domain"] = QList2QJsonArray<QString>(status->domainListDirect);
status->routingRules += tmp;
}
// def_outbound
if (!status->forTest) status->routingRules += QJsonObject{
{"type", "field"},
{"port", "0-65535"},
{"outboundTag", dataStore->routing->def_outbound},
};
// final add routing rule
auto routingRules = QString2QJsonObject(dataStore->routing->custom)["rules"].toArray();
if (status->forTest) routingRules = {};
if (!status->forTest) QJSONARRAY_ADD(routingRules, QString2QJsonObject(dataStore->custom_route_global)["rules"].toArray())
QJSONARRAY_ADD(routingRules, status->routingRules)
routing["rules"] = routingRules;
status->result->coreConfig.insert("routing", routing);
// Policy & stats
QJsonObject policy;
QJsonObject levels;
QJsonObject level1;
level1["connIdle"] = 30;
levels["1"] = level1;
policy["levels"] = levels;
QJsonObject policySystem;
policySystem["statsOutboundDownlink"] = true;
policySystem["statsOutboundUplink"] = true;
policy["system"] = policySystem;
status->result->coreConfig.insert("policy", policy);
status->result->coreConfig.insert("stats", QJsonObject());
}
QString BuildChainInternal(int chainId, const QList<std::shared_ptr<ProxyEntity>> &ents,
const std::shared_ptr<BuildConfigStatus> &status) {
QString chainTag = "c-" + Int2String(chainId);
@@ -454,29 +202,14 @@ namespace NekoGui {
// chain rules: past
if (pastExternalStat == 0) {
auto replaced = status->outbounds.last().toObject();
if (IS_NEKO_BOX) {
replaced["detour"] = tagOut;
} else {
replaced["proxySettings"] = QJsonObject{
{"tag", tagOut},
{"transportLayer", true},
};
}
replaced["detour"] = tagOut;
status->outbounds.removeLast();
status->outbounds += replaced;
} else {
if (IS_NEKO_BOX) {
status->routingRules += QJsonObject{
{"inbound", QJsonArray{pastTag + "-mapping"}},
{"outbound", tagOut},
};
} else {
status->routingRules += QJsonObject{
{"type", "field"},
{"inboundTag", QJsonArray{pastTag + "-mapping"}},
{"outboundTag", tagOut},
};
}
status->routingRules += QJsonObject{
{"inbound", QJsonArray{pastTag + "-mapping"}},
{"outbound", tagOut},
};
}
} else {
// index == 0 means last profile in chain / not chain
@@ -515,43 +248,20 @@ namespace NekoGui {
if (thisExternalStat == 2) dataStore->need_keep_vpn_off = true;
if (thisExternalStat == 1) {
// mapping
if (IS_NEKO_BOX) {
status->inbounds += QJsonObject{
{"type", "direct"},
{"tag", tagOut + "-mapping"},
{"listen", "127.0.0.1"},
{"listen_port", ext_mapping_port},
{"override_address", ent->bean->serverAddress},
{"override_port", ent->bean->serverPort},
};
} else {
status->inbounds += QJsonObject{
{"protocol", "dokodemo-door"},
{"tag", tagOut + "-mapping"},
{"listen", "127.0.0.1"},
{"port", ext_mapping_port},
{"settings", QJsonObject{
// to
{"address", ent->bean->serverAddress},
{"port", ent->bean->serverPort},
{"network", "tcp,udp"},
}},
};
}
status->inbounds += QJsonObject{
{"type", "direct"},
{"tag", tagOut + "-mapping"},
{"listen", "127.0.0.1"},
{"listen_port", ext_mapping_port},
{"override_address", ent->bean->serverAddress},
{"override_port", ent->bean->serverPort},
};
// no chain rule and not outbound, so need to set to direct
if (isFirstProfile) {
if (IS_NEKO_BOX) {
status->routingRules += QJsonObject{
{"inbound", QJsonArray{tagOut + "-mapping"}},
{"outbound", "direct"},
};
} else {
status->routingRules += QJsonObject{
{"type", "field"},
{"inboundTag", QJsonArray{tagOut + "-mapping"}},
{"outboundTag", "direct"},
};
}
status->routingRules += QJsonObject{
{"inbound", QJsonArray{tagOut + "-mapping"}},
{"outbound", "direct"},
};
}
}
@@ -574,23 +284,11 @@ namespace NekoGui {
status->result->extRs.emplace_back(std::make_shared<NekoGui_fmt::ExternalBuildResult>(extR));
// SOCKS OUTBOUND
if (IS_NEKO_BOX) {
outbound["type"] = "socks";
outbound["server"] = "127.0.0.1";
outbound["server_port"] = ext_socks_port;
} else {
outbound["protocol"] = "socks";
QJsonObject settings;
QJsonArray servers;
QJsonObject server;
server["address"] = "127.0.0.1";
server["port"] = ext_socks_port;
servers.push_back(server);
settings["servers"] = servers;
outbound["settings"] = settings;
}
outbound["type"] = "socks";
outbound["server"] = "127.0.0.1";
outbound["server_port"] = ext_socks_port;
} else {
const auto coreR = IS_NEKO_BOX ? ent->bean->BuildCoreObjSingBox() : ent->bean->BuildCoreObjV2Ray();
const auto coreR = ent->bean->BuildCoreObjSingBox();
if (coreR.outbound.isEmpty()) {
status->result->error = "unsupported outbound";
return {};
@@ -613,14 +311,8 @@ namespace NekoGui {
needMux &= dataStore->mux_concurrency > 0;
if (stream != nullptr) {
if (IS_NEKO_BOX) {
if (stream->network == "grpc" || stream->network == "quic" || (stream->network == "http" && stream->security == "tls")) {
needMux = false;
}
} else {
if (stream->network == "grpc" || stream->network == "quic") {
needMux = false;
}
if (stream->network == "grpc" || stream->network == "quic" || (stream->network == "http" && stream->security == "tls")) {
needMux = false;
}
if (stream->multiplex_status == 0) {
if (!dataStore->mux_default_on) needMux = false;
@@ -635,32 +327,18 @@ namespace NekoGui {
}
// common
if (IS_NEKO_BOX) {
// apply domain_strategy
outbound["domain_strategy"] = dataStore->routing->outbound_domain_strategy;
// apply mux
if (!muxApplied && needMux) {
auto muxObj = QJsonObject{
{"enabled", true},
{"protocol", dataStore->mux_protocol},
{"padding", dataStore->mux_padding},
{"max_streams", dataStore->mux_concurrency},
};
outbound["multiplex"] = muxObj;
muxApplied = true;
}
} else {
// apply domain_strategy
if (!status->forTest) outbound["domainStrategy"] = dataStore->routing->outbound_domain_strategy;
// apply mux
if (!muxApplied && needMux) {
auto muxObj = QJsonObject{
{"enabled", true},
{"concurrency", dataStore->mux_concurrency},
};
outbound["mux"] = muxObj;
muxApplied = true;
}
// apply domain_strategy
outbound["domain_strategy"] = dataStore->routing->outbound_domain_strategy;
// apply mux
if (!muxApplied && needMux) {
auto muxObj = QJsonObject{
{"enabled", true},
{"protocol", dataStore->mux_protocol},
{"padding", dataStore->mux_padding},
{"max_streams", dataStore->mux_concurrency},
};
outbound["multiplex"] = muxObj;
muxApplied = true;
}
// apply custom outbound settings
@@ -720,7 +398,7 @@ namespace NekoGui {
}
// tun-in
if (IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
if (dataStore->vpn_internal_tun && dataStore->spmode_vpn && !status->forTest) {
QJsonObject inboundObj;
inboundObj["tag"] = "tun-in";
inboundObj["type"] = "tun";
@@ -869,7 +547,7 @@ namespace NekoGui {
};
// Fakedns
if (dataStore->fake_dns && IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
if (dataStore->fake_dns && dataStore->vpn_internal_tun && dataStore->spmode_vpn && !status->forTest) {
dnsServers += QJsonObject{
{"tag", "dns-fake"},
{"address", "fakeip"},
@@ -911,7 +589,7 @@ namespace NekoGui {
}
// fakedns rule
if (dataStore->fake_dns && IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
if (dataStore->fake_dns && dataStore->vpn_internal_tun && dataStore->spmode_vpn && !status->forTest) {
dnsRules += QJsonObject{
{"inbound", "tun-in"},
{"server", "dns-fake"},
@@ -969,7 +647,7 @@ namespace NekoGui {
};
// tun user rule
if (IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
if (dataStore->vpn_internal_tun && dataStore->spmode_vpn && !status->forTest) {
auto match_out = dataStore->vpn_rule_white ? "proxy" : "bypass";
QString process_name_rule = dataStore->vpn_rule_process.trimmed();

View File

@@ -46,8 +46,6 @@ namespace NekoGui {
std::shared_ptr<BuildConfigResult> BuildConfig(const std::shared_ptr<ProxyEntity> &ent, bool forTest, bool forExport);
void BuildConfigV2Ray(const std::shared_ptr<BuildConfigStatus> &status);
void BuildConfigSingBox(const std::shared_ptr<BuildConfigStatus> &status);
QString BuildChain(int chainId, const std::shared_ptr<BuildConfigStatus> &status);

View File

@@ -59,8 +59,6 @@ namespace NekoGui_fmt {
virtual int NeedExternal(bool isFirstProfile) { return 0; };
virtual CoreObjOutboundBuildResult BuildCoreObjV2Ray() { return {}; };
virtual CoreObjOutboundBuildResult BuildCoreObjSingBox() { return {}; };
virtual ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) { return {}; };

View File

@@ -1,211 +0,0 @@
#include "db/ProxyEntity.hpp"
#include "fmt/includes.h"
#define MAKE_SETTINGS_STREAM_SETTINGS \
outbound["settings"] = settings; \
auto streamSettings = stream->BuildStreamSettingsV2Ray(); \
outbound["streamSettings"] = streamSettings;
namespace NekoGui_fmt {
QJsonObject V2rayStreamSettings::BuildStreamSettingsV2Ray() {
QJsonObject streamSettings{{"network", network}};
if (network == "ws") {
QJsonObject ws;
if (!host.isEmpty()) ws["headers"] = QJsonObject{{"Host", host}};
// ws path & ed
if (!path.isEmpty()) ws["path"] = path;
streamSettings["wsSettings"] = ws;
} else if (network == "http") {
QJsonObject http;
if (!path.isEmpty()) http["path"] = path;
if (!host.isEmpty()) http["host"] = QList2QJsonArray(host.split(","));
streamSettings["httpSettings"] = http;
} else if (network == "grpc") {
QJsonObject grpc;
if (!path.isEmpty()) grpc["serviceName"] = path;
streamSettings["grpcSettings"] = grpc;
} else if (network == "quic") {
QJsonObject quic;
if (!header_type.isEmpty()) quic["header"] = QJsonObject{{"type", header_type}};
if (!path.isEmpty()) quic["key"] = path;
if (!host.isEmpty()) quic["security"] = host;
streamSettings["quicSettings"] = quic;
} else if (network == "tcp" && !header_type.isEmpty()) {
QJsonObject header{{"type", header_type}};
if (header_type == "http") {
header["request"] = QJsonObject{
{"path", QList2QJsonArray(path.split(","))},
{"headers", QJsonObject{{"Host", QList2QJsonArray(host.split(","))}}},
};
}
streamSettings["tcpSettings"] = QJsonObject{{"header", header}};
}
if (security == "tls") {
QJsonObject tls;
if (!utlsFingerprint.isEmpty()) tls["fingerprint"] = utlsFingerprint;
if (!sni.trimmed().isEmpty()) tls["serverName"] = sni;
if (reality_pbk.trimmed().isEmpty()) {
if (allow_insecure || NekoGui::dataStore->skip_cert) tls["allowInsecure"] = true;
if (!alpn.trimmed().isEmpty()) tls["alpn"] = QList2QJsonArray(alpn.split(","));
if (!certificate.trimmed().isEmpty()) {
tls["disableSystemRoot"] = true;
tls["certificates"] = QJsonArray{
QJsonObject{
{"usage", "verify"},
{"certificate", QList2QJsonArray(SplitLines(certificate.trimmed()))},
},
};
}
streamSettings["tlsSettings"] = tls;
streamSettings["security"] = "tls";
} else {
tls["publicKey"] = reality_pbk;
tls["shortId"] = reality_sid;
tls["spiderX"] = reality_spx;
if (utlsFingerprint.isEmpty()) tls["fingerprint"] = "chrome";
streamSettings["realitySettings"] = tls;
streamSettings["security"] = "reality";
}
}
return streamSettings;
}
CoreObjOutboundBuildResult SocksHttpBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound;
outbound["protocol"] = socks_http_type == type_HTTP ? "http" : "socks";
QJsonObject settings;
QJsonArray servers;
QJsonObject server;
server["address"] = serverAddress;
server["port"] = serverPort;
QJsonArray users;
QJsonObject user;
user["user"] = username;
user["pass"] = password;
users.push_back(user);
if (!username.isEmpty() && !password.isEmpty()) server["users"] = users;
servers.push_back(server);
settings["servers"] = servers;
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult ShadowSocksBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound{{"protocol", "shadowsocks"}};
QJsonObject settings;
QJsonArray servers;
QJsonObject server;
server["address"] = serverAddress;
server["port"] = serverPort;
server["method"] = method;
server["password"] = password;
if (uot != 0) {
server["uot"] = true;
server["UoTVersion"] = uot;
} else {
server["uot"] = false;
}
servers.push_back(server);
settings["servers"] = servers;
if (!plugin.trimmed().isEmpty()) {
settings["plugin"] = SubStrBefore(plugin, ";");
settings["pluginOpts"] = SubStrAfter(plugin, ";");
}
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult VMessBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound{{"protocol", "vmess"}};
QJsonObject settings{
{"vnext", QJsonArray{
QJsonObject{
{"address", serverAddress},
{"port", serverPort},
{"users", QJsonArray{
QJsonObject{
{"id", uuid.trimmed()},
{"alterId", aid},
{"security", security},
}}},
}}}};
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult TrojanVLESSBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound{
{"protocol", proxy_type == proxy_VLESS ? "vless" : "trojan"},
};
QJsonObject settings;
if (proxy_type == proxy_VLESS) {
if (flow == "none") {
flow = "";
}
settings = QJsonObject{
{"vnext", QJsonArray{
QJsonObject{
{"address", serverAddress},
{"port", serverPort},
{"users", QJsonArray{
QJsonObject{
{"id", password.trimmed()},
{"encryption", "none"},
{"flow", flow},
}}},
}}}};
} else {
settings = QJsonObject{
{"servers", QJsonArray{
QJsonObject{
{"address", serverAddress},
{"port", serverPort},
{"password", password},
}}}};
}
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult CustomBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
if (core == "internal") {
result.outbound = QString2QJsonObject(config_simple);
}
return result;
}
} // namespace NekoGui_fmt

View File

@@ -70,19 +70,11 @@ namespace NekoGui_fmt {
return 1;
};
if (IS_NEKO_BOX) {
if (!forceExternal && (proxy_type == proxy_TUIC || hyProtocol == hysteria_protocol_udp)) {
// sing-box support
return 0;
} else {
// hysteria core support
return hysteriaCore();
}
} else if (proxy_type == proxy_TUIC) {
return tuicCore();
} else if (proxy_type == proxy_Hysteria2) {
return hysteria2Core();
if (!forceExternal && (proxy_type == proxy_TUIC || hyProtocol == hysteria_protocol_udp)) {
// sing-box support
return 0;
} else {
// hysteria core support
return hysteriaCore();
}
}

View File

@@ -24,7 +24,7 @@ namespace NekoGui_fmt {
QString DisplayType() override {
if (core == "internal") {
auto obj = QString2QJsonObject(config_simple);
return obj[IS_NEKO_BOX ? "type" : "protocol"].toString();
return obj["type"].toString();
} else if (core == "internal-full") {
return software_core_name + " config";
}
@@ -36,11 +36,7 @@ namespace NekoGui_fmt {
QString DisplayAddress() override {
if (core == "internal") {
auto obj = QString2QJsonObject(config_simple);
if (IS_NEKO_BOX) {
return ::DisplayAddress(obj["server"].toString(), obj["server_port"].toInt());
} else {
return {};
}
return ::DisplayAddress(obj["server"].toString(), obj["server_port"].toInt());
} else if (core == "internal-full") {
return {};
}
@@ -52,7 +48,5 @@ namespace NekoGui_fmt {
ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
};
} // namespace NekoGui_fmt

View File

@@ -1,15 +1,6 @@
#pragma once
namespace Preset {
namespace Xray {
inline QStringList UtlsFingerPrint = {"", "chrome", "firefox", "edge", "safari", "360", "qq", "ios", "android", "random", "randomized"};
inline QStringList ShadowsocksMethods = {"aes-128-gcm", "aes-256-gcm", "aes-192-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305",
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305",
"aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb",
"rc4", "rc4-md5", "bf-cfb", "chacha20", "chacha20-ietf", "xchacha20", "none"};
inline QStringList Flows = {"xtls-rprx-vision", "xtls-rprx-vision-udp443"};
} // namespace Xray
namespace SingBox {
inline QStringList VpnImplementation = {"gvisor", "system", "mixed"};
inline QStringList DomainStrategy = {"", "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6"};

View File

@@ -23,8 +23,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return "Shadowsocks"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link);

View File

@@ -26,8 +26,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return socks_http_type == type_HTTP ? "HTTP" : "Socks"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link);

View File

@@ -24,8 +24,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return proxy_type == proxy_VLESS ? "VLESS" : "Trojan"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link);

View File

@@ -49,8 +49,6 @@ namespace NekoGui_fmt {
_add(new configItem("mux_s", &multiplex_status, itemType::integer));
}
QJsonObject BuildStreamSettingsV2Ray();
void BuildStreamSettingsSingBox(QJsonObject *outbound);
};

View File

@@ -21,8 +21,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return "VMess"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link);

View File

@@ -18,7 +18,7 @@ namespace NekoGui_network {
if (NekoGui::dataStore->sub_use_proxy) {
QNetworkProxy p;
// Note: sing-box mixed socks5 protocol error
p.setType(IS_NEKO_BOX ? QNetworkProxy::HttpProxy : QNetworkProxy::Socks5Proxy);
p.setType(QNetworkProxy::HttpProxy);
p.setHostName("127.0.0.1");
p.setPort(NekoGui::dataStore->inbound_socks_port);
if (NekoGui::dataStore->inbound_auth->NeedAuth()) {

View File

@@ -237,7 +237,6 @@ namespace NekoGui {
_add(new configItem("current_group", &current_group, itemType::integer));
_add(new configItem("inbound_address", &inbound_address, itemType::string));
_add(new configItem("inbound_socks_port", &inbound_socks_port, itemType::integer));
_add(new configItem("inbound_http_port", &inbound_http_port, itemType::integer));
_add(new configItem("log_level", &log_level, itemType::string));
_add(new configItem("mux_protocol", &mux_protocol, itemType::string));
_add(new configItem("mux_concurrency", &mux_concurrency, itemType::integer));
@@ -284,12 +283,7 @@ namespace NekoGui {
_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));
_add(new configItem("core_ray_freedom_domainStrategy", &core_ray_freedom_domainStrategy, itemType::string));
_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));
#endif
}
void DataStore::UpdateStartedId(int id) {
@@ -310,11 +304,7 @@ namespace NekoGui {
if (isDefault) {
QString version = SubStrBefore(NKR_VERSION, "-");
if (!version.contains(".")) version = "2.0";
if (IS_NEKO_BOX) {
return "NekoBox/PC/" + version + " (Prefer ClashMeta Format)";
} else {
return "NekoRay/PC/" + version + " (Prefer ClashMeta Format)";
}
return "NekoBox/PC/" + version + " (Prefer ClashMeta Format)";
}
return user_agent;
}
@@ -335,10 +325,8 @@ namespace NekoGui {
"domain:firebase.io\n"
"domain:crashlytics.com\n";
}
if (IS_NEKO_BOX) {
if (!Preset::SingBox::DomainStrategy.contains(domain_strategy)) domain_strategy = "";
if (!Preset::SingBox::DomainStrategy.contains(outbound_domain_strategy)) outbound_domain_strategy = "";
}
if (!Preset::SingBox::DomainStrategy.contains(domain_strategy)) domain_strategy = "";
if (!Preset::SingBox::DomainStrategy.contains(outbound_domain_strategy)) outbound_domain_strategy = "";
_add(new configItem("direct_ip", &this->direct_ip, itemType::string));
_add(new configItem("direct_domain", &this->direct_domain, itemType::string));
_add(new configItem("proxy_ip", &this->proxy_ip, itemType::string));

View File

@@ -17,7 +17,5 @@ namespace NekoGui {
bool IsAdmin();
} // namespace NekoGui
#define IS_NEKO_BOX (NekoGui::coreType == NekoGui::CoreType::SING_BOX)
#define IS_NEKO_BOX_INTERNAL_TUN (IS_NEKO_BOX && NekoGui::dataStore->vpn_internal_tun)
#define ROUTES_PREFIX_NAME QString(IS_NEKO_BOX ? "routes_box" : "routes")
#define ROUTES_PREFIX_NAME QString("routes_box")
#define ROUTES_PREFIX QString(ROUTES_PREFIX_NAME + "/")

View File

@@ -93,7 +93,7 @@ namespace NekoGui {
// Saved
// Misc
QString log_level = "warning";
QString log_level = "info";
QString test_latency_url = "http://cp.cloudflare.com/";
QString test_download_url = "http://cachefly.cachefly.net/10mb.test";
int test_download_timeout = 30;
@@ -102,7 +102,7 @@ namespace NekoGui {
int traffic_loop_interval = 1000;
bool connection_statistics = false;
int current_group = 0; // group id
QString mux_protocol = "";
QString mux_protocol = "h2mux";
bool mux_padding = false;
int mux_concurrency = 8;
bool mux_default_on = false;
@@ -136,7 +136,6 @@ namespace NekoGui {
// Socks & HTTP Inbound
QString inbound_address = "127.0.0.1";
int inbound_socks_port = 2080; // or Mixed
int inbound_http_port = 2081;
InboundAuthorization *inbound_auth = new InboundAuthorization;
QString custom_inbound = "{\"inbounds\": []}";
@@ -166,9 +165,6 @@ namespace NekoGui {
int core_box_clash_api = -9090;
QString core_box_clash_api_secret = "";
QString core_box_underlying_dns = "";
bool core_ray_direct_dns = false;
bool core_ray_windows_disable_auto_interface = false;
QString core_ray_freedom_domainStrategy = "";
// Other Core
ExtraCore *extraCore = new ExtraCore;

View File

@@ -8,8 +8,8 @@
//
inline QString software_name = "NekoRay";
inline QString software_core_name = "Xray";
inline QString software_name = "NekoBox";
inline QString software_core_name = "sing-box";
// Main Functions

View File

@@ -147,8 +147,6 @@ namespace NekoGui_sys {
v2ray_asset_dir = QFileInfo(v2ray_asset_dir).absolutePath();
env << "XRAY_LOCATION_ASSET=" + v2ray_asset_dir;
}
if (NekoGui::dataStore->core_ray_direct_dns) env << "NKR_CORE_RAY_DIRECT_DNS=1";
if (NekoGui::dataStore->core_ray_windows_disable_auto_interface) env << "NKR_CORE_RAY_WINDOWS_DISABLE_AUTO_INTERFACE=1";
//
ExternalProcess::Start();
write((NekoGui::dataStore->core_token + "\n").toUtf8());

View File

@@ -11,18 +11,10 @@
<source>Enable</source>
<translation>فعال کردن</translation>
</message>
<message>
<source>HTTP Listen Port</source>
<translation>پورت HTTP درحال شنود</translation>
</message>
<message>
<source>Listen Address</source>
<translation>آدرس درحال شنود</translation>
</message>
<message>
<source>Socks Listen Port</source>
<translation>پورت ساکس درحال شنود</translation>
</message>
<message>
<source>concurrency</source>
<translation>همزمانی</translation>
@@ -197,16 +189,6 @@
<source>Override underlying DNS</source>
<translation type="unfinished">لغو دی ان اس زیربنایی</translation>
</message>
<message>
<source>It is recommended to leave it blank, but it sometimes does not work, at this time you can set this option.
For NekoRay, this rewrites the underlying(localhost) DNS in Tun Mode.
For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mode, and also URL Test.</source>
<translation type="unfinished">پیشنهاد میشود که این گزینه را انتخاب نشده باقی بگذارید ، اما گاهی اوقات کار نمیکند در این مواقع شما میتوانید این گزینه را انتخاب کنید ، برای Nekoray این گزینه دی ان اس زیربنایی را در حالت تونل بازنویسی میکند ، و برای NekoBox این گزینه دی ان اس زیربنایی را هم در حالت تونل و هم در حالت معمولی و تست آدرس بازنویسی میکند</translation>
</message>
<message>
<source>If you Tun Mode is not working, try to change this option.</source>
<translation type="unfinished">اگر حالت تونل برای شما کار نمیکند ، این گزینه را تغییر دهید</translation>
</message>
<message>
<source>Default On</source>
<translation type="unfinished">به صورت پیشفرض فعال</translation>
@@ -243,6 +225,10 @@ For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mod
<source>Old Share Link Format</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Mixed (SOCKS+HTTP) Listen Port</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DialogEditGroup</name>
@@ -1368,14 +1354,6 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>Imported %1 profile(s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Http inbound is not enabled, can&apos;t set system proxy.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Settings</source>
<translation>تنظیمات</translation>
</message>
<message>
<source>Current server is incompatible with Tun. Please stop the server first, enable Tun Mode, and then restart.</source>
<translation type="unfinished"></translation>
@@ -1384,11 +1362,6 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>Not Running</source>
<translation>در حال اجرا نیست</translation>
</message>
<message>
<source>None</source>
<translatorcomment>هیچ یک</translatorcomment>
<translation>هیچ یک</translation>
</message>
<message>
<source>Select</source>
<translation>انتخاب</translation>

View File

@@ -23,14 +23,6 @@
<source>Edit</source>
<translation>Изменить</translation>
</message>
<message>
<source>Socks Listen Port</source>
<translation>Адрес входящих SOCKS</translation>
</message>
<message>
<source>HTTP Listen Port</source>
<translation>Адрес входящих HTTP</translation>
</message>
<message>
<source>Enable</source>
<translation>Вкл</translation>
@@ -211,18 +203,6 @@
<source>Override underlying DNS</source>
<translation>Переопределить нижестоящий DNS</translation>
</message>
<message>
<source>It is recommended to leave it blank, but it sometimes does not work, at this time you can set this option.
For NekoRay, this rewrites the underlying(localhost) DNS in Tun Mode.
For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mode, and also URL Test.</source>
<translation>Рекомендуется оставить параметр пустым, но иногда это не срабатывает как надо, и в таком случае можно использовать эту опцию.
Для NekoRay это переопределяет нижестоящий (localhost) DNS в Tun режиме.
Для NekoBox это переопределяет нижестоящий (localhost) DNS в Tun режиме, нормальном режиме, а также при URL тесте.</translation>
</message>
<message>
<source>If you Tun Mode is not working, try to change this option.</source>
<translation>Если TUN-режим не работает, попробуйте изменить эту опцию.</translation>
</message>
<message>
<source>Timeout (s)</source>
<translation>Таймаут (с)</translation>
@@ -243,6 +223,10 @@ For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mod
<source>Old Share Link Format</source>
<translation>Поделиться ссылкой в старом формате</translation>
</message>
<message>
<source>Mixed (SOCKS+HTTP) Listen Port</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DialogEditGroup</name>
@@ -1394,14 +1378,6 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
<source>Imported %1 profile(s)</source>
<translation>Импортирован(ы) %1 профиль(ей)</translation>
</message>
<message>
<source>Http inbound is not enabled, can&apos;t set system proxy.</source>
<translation>HTTP inbound не включен в настройках, невозможно установить системный прокси.</translation>
</message>
<message>
<source>Settings</source>
<translation>Настройки</translation>
</message>
<message>
<source>Please run NekoBox as admin</source>
<translation>Пожалуйста, запустите NekoBox с правами администратора</translation>
@@ -1414,10 +1390,6 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
<source>Not Running</source>
<translation>Не запущен</translation>
</message>
<message>
<source>None</source>
<translation>Нет</translation>
</message>
<message>
<source>Select</source>
<translation>Выбор</translation>

View File

@@ -11,18 +11,10 @@
<source>Enable</source>
<translation></translation>
</message>
<message>
<source>HTTP Listen Port</source>
<translation>HTTP </translation>
</message>
<message>
<source>Listen Address</source>
<translation></translation>
</message>
<message>
<source>Socks Listen Port</source>
<translation>Socks </translation>
</message>
<message>
<source>concurrency</source>
<translation></translation>
@@ -203,18 +195,6 @@
<source>Override underlying DNS</source>
<translation> DNS</translation>
</message>
<message>
<source>It is recommended to leave it blank, but it sometimes does not work, at this time you can set this option.
For NekoRay, this rewrites the underlying(localhost) DNS in Tun Mode.
For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mode, and also URL Test.</source>
<translation>
NekoRay Tun underlying(localhost) DNS
NekoBox Tun URL underlying(localhost) DNS</translation>
</message>
<message>
<source>If you Tun Mode is not working, try to change this option.</source>
<translation> Tun </translation>
</message>
<message>
<source>Default On</source>
<translation></translation>
@@ -243,6 +223,10 @@ For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mod
<source>Interval (minute, invalid if less than 30)</source>
<translation> 30 </translation>
</message>
<message>
<source>Mixed (SOCKS+HTTP) Listen Port</source>
<translation>Mixed (SOCKS+HTTP) </translation>
</message>
</context>
<context>
<name>DialogEditGroup</name>
@@ -1210,10 +1194,6 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>Imported %1 profile(s)</source>
<translation> %1 </translation>
</message>
<message>
<source>None</source>
<translation></translation>
</message>
<message>
<source>Unavailable</source>
<translation></translation>

View File

@@ -59,16 +59,8 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
// Common
if (IS_NEKO_BOX) {
ui->groupBox_http->hide();
ui->inbound_socks_port_l->setText(ui->inbound_socks_port_l->text().replace("Socks", "Mixed (SOCKS+HTTP)"));
ui->log_level->addItems(QString("trace debug info warn error fatal panic").split(" "));
ui->mux_protocol->addItems({"h2mux", "smux", "yamux"});
} else {
ui->log_level->addItems({"debug", "info", "warning", "none"});
ui->mux_protocol->hide();
ui->mux_padding->hide();
}
ui->log_level->addItems(QString("trace debug info warn error fatal panic").split(" "));
ui->mux_protocol->addItems({"h2mux", "smux", "yamux"});
refresh_auth();
@@ -76,7 +68,6 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
D_LOAD_COMBO_STRING(log_level)
CACHE.custom_inbound = NekoGui::dataStore->custom_inbound;
D_LOAD_INT(inbound_socks_port)
D_LOAD_INT_ENABLE(inbound_http_port, http_enable)
D_LOAD_INT(test_concurrent)
D_LOAD_INT(test_download_timeout)
D_LOAD_STRING(test_latency_url)
@@ -102,9 +93,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
#endif
// Style
if (IS_NEKO_BOX) {
ui->connection_statistics_box->setDisabled(true);
}
ui->connection_statistics_box->setDisabled(true);
//
D_LOAD_BOOL(check_include_pre)
D_LOAD_BOOL(connection_statistics)
@@ -225,7 +214,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
// Security
ui->utlsFingerprint->addItems(IS_NEKO_BOX ? Preset::SingBox::UtlsFingerPrint : Preset::Xray::UtlsFingerPrint);
ui->utlsFingerprint->addItems(Preset::SingBox::UtlsFingerPrint);
D_LOAD_BOOL(skip_cert)
ui->utlsFingerprint->setCurrentText(NekoGui::dataStore->utlsFingerprint);
@@ -242,7 +231,6 @@ void DialogBasicSettings::accept() {
D_SAVE_COMBO_STRING(log_level)
NekoGui::dataStore->custom_inbound = CACHE.custom_inbound;
D_SAVE_INT(inbound_socks_port)
D_SAVE_INT_ENABLE(inbound_http_port, http_enable)
D_SAVE_INT(test_concurrent)
D_SAVE_INT(test_download_timeout)
D_SAVE_STRING(test_latency_url)
@@ -395,80 +383,39 @@ void DialogBasicSettings::on_core_settings_clicked() {
MyLineEdit *core_box_clash_api;
MyLineEdit *core_box_clash_api_secret;
MyLineEdit *core_box_underlying_dns;
QCheckBox *core_ray_direct_dns;
QCheckBox *core_ray_windows_disable_auto_interface;
QComboBox *core_ray_freedom_domainStrategy;
//
auto core_box_underlying_dns_l = new QLabel(tr("Override underlying DNS"));
core_box_underlying_dns_l->setToolTip(tr(
"It is recommended to leave it blank, but it sometimes does not work, at this time you can set this option.\n"
"For NekoRay, this rewrites the underlying(localhost) DNS in Tun Mode.\n"
"For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mode, and also URL Test."));
core_box_underlying_dns = new MyLineEdit;
core_box_underlying_dns->setText(NekoGui::dataStore->core_box_underlying_dns);
core_box_underlying_dns->setMinimumWidth(300);
layout->addWidget(core_box_underlying_dns_l, ++line, 0);
layout->addWidget(core_box_underlying_dns, line, 1);
//
if (IS_NEKO_BOX) {
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(NekoGui::dataStore->core_box_clash_api > 0);
layout->addWidget(core_box_enable_clash_api_l, ++line, 0);
layout->addWidget(core_box_enable_clash_api, line, 1);
//
auto core_box_clash_api_l = new QLabel("Clash API Listen Port");
core_box_clash_api = new MyLineEdit;
core_box_clash_api->setText(Int2String(std::abs(NekoGui::dataStore->core_box_clash_api)));
layout->addWidget(core_box_clash_api_l, ++line, 0);
layout->addWidget(core_box_clash_api, line, 1);
//
auto core_box_clash_api_secret_l = new QLabel("Clash API Secret");
core_box_clash_api_secret = new MyLineEdit;
core_box_clash_api_secret->setText(NekoGui::dataStore->core_box_clash_api_secret);
layout->addWidget(core_box_clash_api_secret_l, ++line, 0);
layout->addWidget(core_box_clash_api_secret, line, 1);
} else {
auto core_ray_direct_dns_l = new QLabel("NKR_CORE_RAY_DIRECT_DNS");
core_ray_direct_dns_l->setToolTip(tr("If you Tun Mode is not working, try to change this option."));
core_ray_direct_dns = new QCheckBox;
core_ray_direct_dns->setChecked(NekoGui::dataStore->core_ray_direct_dns);
connect(core_ray_direct_dns, &QCheckBox::clicked, this, [&] { CACHE.needRestart = true; });
layout->addWidget(core_ray_direct_dns_l, ++line, 0);
layout->addWidget(core_ray_direct_dns, line, 1);
//
auto core_ray_freedom_domainStrategy_l = new QLabel("Freedom Strategy");
core_ray_freedom_domainStrategy = new QComboBox;
core_ray_freedom_domainStrategy->addItems({"", "AsIs", "UseIP", "UseIPv4", "UseIPv6"});
core_ray_freedom_domainStrategy->setCurrentText(NekoGui::dataStore->core_ray_freedom_domainStrategy);
layout->addWidget(core_ray_freedom_domainStrategy_l, ++line, 0);
layout->addWidget(core_ray_freedom_domainStrategy, line, 1);
#ifdef Q_OS_WIN
auto core_ray_windows_disable_auto_interface_l = new QLabel("NKR_CORE_RAY_WINDOWS_DISABLE_AUTO_INTERFACE");
core_ray_windows_disable_auto_interface_l->setToolTip(tr("If you Tun Mode is not working, try to change this option."));
core_ray_windows_disable_auto_interface = new QCheckBox;
core_ray_windows_disable_auto_interface->setChecked(NekoGui::dataStore->core_ray_windows_disable_auto_interface);
connect(core_ray_windows_disable_auto_interface, &QCheckBox::clicked, this, [&] { CACHE.needRestart = true; });
layout->addWidget(core_ray_windows_disable_auto_interface_l, ++line, 0);
layout->addWidget(core_ray_windows_disable_auto_interface, line, 1);
#endif
}
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(NekoGui::dataStore->core_box_clash_api > 0);
layout->addWidget(core_box_enable_clash_api_l, ++line, 0);
layout->addWidget(core_box_enable_clash_api, line, 1);
//
auto core_box_clash_api_l = new QLabel("Clash API Listen Port");
core_box_clash_api = new MyLineEdit;
core_box_clash_api->setText(Int2String(std::abs(NekoGui::dataStore->core_box_clash_api)));
layout->addWidget(core_box_clash_api_l, ++line, 0);
layout->addWidget(core_box_clash_api, line, 1);
//
auto core_box_clash_api_secret_l = new QLabel("Clash API Secret");
core_box_clash_api_secret = new MyLineEdit;
core_box_clash_api_secret->setText(NekoGui::dataStore->core_box_clash_api_secret);
layout->addWidget(core_box_clash_api_secret_l, ++line, 0);
layout->addWidget(core_box_clash_api_secret, line, 1);
//
auto box = new QDialogButtonBox;
box->setOrientation(Qt::Horizontal);
box->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
connect(box, &QDialogButtonBox::accepted, w, [=] {
NekoGui::dataStore->core_box_underlying_dns = core_box_underlying_dns->text();
if (IS_NEKO_BOX) {
NekoGui::dataStore->core_box_clash_api = core_box_clash_api->text().toInt() * (core_box_enable_clash_api->isChecked() ? 1 : -1);
NekoGui::dataStore->core_box_clash_api_secret = core_box_clash_api_secret->text();
} else {
NekoGui::dataStore->core_ray_direct_dns = core_ray_direct_dns->isChecked();
NekoGui::dataStore->core_ray_freedom_domainStrategy = core_ray_freedom_domainStrategy->currentText();
#ifdef Q_OS_WIN
NekoGui::dataStore->core_ray_windows_disable_auto_interface = core_ray_windows_disable_auto_interface->isChecked();
#endif
}
NekoGui::dataStore->core_box_clash_api = core_box_clash_api->text().toInt() * (core_box_enable_clash_api->isChecked() ? 1 : -1);
NekoGui::dataStore->core_box_clash_api_secret = core_box_clash_api_secret->text();
MW_dialog_message(Dialog_DialogBasicSettings, "UpdateDataStore");
w->accept();
});

View File

@@ -95,7 +95,7 @@
<item>
<widget class="QLabel" name="inbound_socks_port_l">
<property name="text">
<string>Socks Listen Port</string>
<string>Mixed (SOCKS+HTTP) Listen Port</string>
</property>
</widget>
</item>
@@ -112,36 +112,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_http">
<layout class="QHBoxLayout" name="horizontalLayout_16">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>HTTP Listen Port</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="inbound_http_port">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="http_enable">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
@@ -709,8 +679,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>198</width>
<height>58</height>
<width>632</width>
<height>299</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">

View File

@@ -22,19 +22,13 @@ DialogManageRoutes::DialogManageRoutes(QWidget *parent) : QDialog(parent), ui(ne
QStringList qsValue = {""};
QString dnsHelpDocumentUrl;
if (IS_NEKO_BOX) {
ui->outbound_domain_strategy->addItems(Preset::SingBox::DomainStrategy);
ui->domainStrategyCombo->addItems(Preset::SingBox::DomainStrategy);
qsValue += QString("prefer_ipv4 prefer_ipv6 ipv4_only ipv6_only").split(" ");
ui->dns_object->setPlaceholderText(DecodeB64IfValid("ewogICJzZXJ2ZXJzIjogW10sCiAgInJ1bGVzIjogW10sCiAgImZpbmFsIjogIiIsCiAgInN0cmF0ZWd5IjogIiIsCiAgImRpc2FibGVfY2FjaGUiOiBmYWxzZSwKICAiZGlzYWJsZV9leHBpcmUiOiBmYWxzZSwKICAiaW5kZXBlbmRlbnRfY2FjaGUiOiBmYWxzZSwKICAicmV2ZXJzZV9tYXBwaW5nIjogZmFsc2UsCiAgImZha2VpcCI6IHt9Cn0="));
dnsHelpDocumentUrl = "https://sing-box.sagernet.org/configuration/dns/";
} else {
ui->outbound_domain_strategy->addItems({"AsIs", "UseIPv4", "UseIPv6", "PreferIPv4", "PreferIPv6"});
ui->domainStrategyCombo->addItems({"AsIs", "IPIfNonMatch", "IPOnDemand"});
qsValue += QString("use_ip use_ip4 use_ip6").split(" ");
ui->dns_object->setPlaceholderText(DecodeB64IfValid("ewogICJzZXJ2ZXJzIjogW10KfQ=="));
dnsHelpDocumentUrl = "https://www.v2fly.org/config/dns.html";
}
//
ui->outbound_domain_strategy->addItems(Preset::SingBox::DomainStrategy);
ui->domainStrategyCombo->addItems(Preset::SingBox::DomainStrategy);
qsValue += QString("prefer_ipv4 prefer_ipv6 ipv4_only ipv6_only").split(" ");
ui->dns_object->setPlaceholderText(DecodeB64IfValid("ewogICJzZXJ2ZXJzIjogW10sCiAgInJ1bGVzIjogW10sCiAgImZpbmFsIjogIiIsCiAgInN0cmF0ZWd5IjogIiIsCiAgImRpc2FibGVfY2FjaGUiOiBmYWxzZSwKICAiZGlzYWJsZV9leHBpcmUiOiBmYWxzZSwKICAiaW5kZXBlbmRlbnRfY2FjaGUiOiBmYWxzZSwKICAicmV2ZXJzZV9tYXBwaW5nIjogZmFsc2UsCiAgImZha2VpcCI6IHt9Cn0="));
dnsHelpDocumentUrl = "https://sing-box.sagernet.org/configuration/dns/";
//
ui->direct_dns_strategy->addItems(qsValue);
ui->remote_dns_strategy->addItems(qsValue);
//

View File

@@ -20,7 +20,6 @@ DialogVPNSettings::DialogVPNSettings(QWidget *parent) : QDialog(parent), ui(new
ui->hide_console->setVisible(false);
#endif
ui->strict_route->setChecked(NekoGui::dataStore->vpn_strict_route);
ui->single_core->setVisible(IS_NEKO_BOX);
ui->single_core->setChecked(NekoGui::dataStore->vpn_internal_tun);
//
D_LOAD_STRING_PLAIN(vpn_rule_cidr)

View File

@@ -62,7 +62,7 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
ui->host_l->setVisible(false);
}
// 传输设置 ED
if (txt == "ws" && IS_NEKO_BOX) {
if (txt == "ws") {
ui->ws_early_data_length->setVisible(true);
ui->ws_early_data_length_l->setVisible(true);
ui->ws_early_data_name->setVisible(true);
@@ -74,11 +74,7 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
ui->ws_early_data_name_l->setVisible(false);
}
// 传输设置 for NekoBox
if (IS_NEKO_BOX) {
if (!ui->utlsFingerprint->count()) ui->utlsFingerprint->addItems(Preset::SingBox::UtlsFingerPrint);
} else {
if (!ui->utlsFingerprint->count()) ui->utlsFingerprint->addItems(Preset::Xray::UtlsFingerPrint);
}
if (!ui->utlsFingerprint->count()) ui->utlsFingerprint->addItems(Preset::SingBox::UtlsFingerPrint);
// 传输设置 是否可见
int networkBoxVisible = 0;
for (auto label: ui->network_box->findChildren<QLabel *>()) {
@@ -89,19 +85,13 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
});
ui->network->removeItem(0);
// if (IS_NEKO_BOX) {
// ui->network->addItem("httpupgrade");
// }
// security changed
connect(ui->security, &QComboBox::currentTextChanged, this, [=](const QString &txt) {
if (txt == "tls") {
ui->security_box->setVisible(true);
ui->tls_camouflage_box->setVisible(true);
if (IS_NEKO_BOX) {
ui->reality_spx->hide();
ui->reality_spx_l->hide();
}
ui->reality_spx->hide();
ui->reality_spx_l->hide();
} else {
ui->security_box->setVisible(false);
ui->tls_camouflage_box->setVisible(false);
@@ -286,47 +276,43 @@ void DialogEditProfile::typeSelected(const QString &newType) {
ADD_ASTERISK(this)
// 设置 for NekoBox
if (IS_NEKO_BOX) {
if (type == "vmess" || type == "vless") {
ui->packet_encoding->setVisible(true);
ui->packet_encoding_l->setVisible(true);
} else {
ui->packet_encoding->setVisible(false);
ui->packet_encoding_l->setVisible(false);
}
if (type == "vmess" || type == "vless" || type == "trojan") {
ui->network_l->setVisible(true);
ui->network->setVisible(true);
ui->network_box->setVisible(true);
} else {
ui->network_l->setVisible(false);
ui->network->setVisible(false);
ui->network_box->setVisible(false);
}
if (type == "vmess" || type == "vless" || type == "trojan" || type == "http") {
ui->security->setVisible(true);
ui->security_l->setVisible(true);
} else {
ui->security->setVisible(false);
ui->security_l->setVisible(false);
}
if (type == "vmess" || type == "vless" || type == "trojan" || type == "shadowsocks") {
ui->multiplex->setVisible(true);
ui->multiplex_l->setVisible(true);
} else {
ui->multiplex->setVisible(false);
ui->multiplex_l->setVisible(false);
}
// 设置 是否可见
int streamBoxVisible = 0;
for (auto label: ui->stream_box->findChildren<QLabel *>()) {
if (!label->isHidden()) streamBoxVisible++;
}
ui->stream_box->setVisible(streamBoxVisible);
if (type == "vmess" || type == "vless") {
ui->packet_encoding->setVisible(true);
ui->packet_encoding_l->setVisible(true);
} else {
ui->packet_encoding->setVisible(false);
ui->packet_encoding_l->setVisible(false);
}
if (type == "vmess" || type == "vless" || type == "trojan") {
ui->network_l->setVisible(true);
ui->network->setVisible(true);
ui->network_box->setVisible(true);
} else {
ui->network_l->setVisible(false);
ui->network->setVisible(false);
ui->network_box->setVisible(false);
}
if (type == "vmess" || type == "vless" || type == "trojan" || type == "http") {
ui->security->setVisible(true);
ui->security_l->setVisible(true);
} else {
ui->security->setVisible(false);
ui->security_l->setVisible(false);
}
if (type == "vmess" || type == "vless" || type == "trojan" || type == "shadowsocks") {
ui->multiplex->setVisible(true);
ui->multiplex_l->setVisible(true);
} else {
ui->multiplex->setVisible(false);
ui->multiplex_l->setVisible(false);
}
// 设置 是否可见
int streamBoxVisible = 0;
for (auto label: ui->stream_box->findChildren<QLabel *>()) {
if (!label->isHidden()) streamBoxVisible++;
}
ui->stream_box->setVisible(streamBoxVisible);
// 载入 type 之后,有些类型没有右边的设置
auto rightNoBox = (ui->stream_box->isHidden() && ui->network_box->isHidden() && ui->security_box->isHidden());

View File

@@ -245,6 +245,11 @@
<string notr="true">ws</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">httpupgrade</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">http</string>

View File

@@ -60,7 +60,6 @@ void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
ui->heartbeat->hide();
ui->heartbeat_l->hide();
ui->uos->hide();
if (!IS_NEKO_BOX) ui->forceExternal->hide();
if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_Hysteria) { // hy1
ui->password->hide();
@@ -77,13 +76,11 @@ void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
ui->alpn->hide();
ui->alpn_l->hide();
ui->TLS->removeItem(ui->alpn_sp);
if (IS_NEKO_BOX) {
ui->disableMtuDiscovery->hide();
ui->connectionReceiveWindow->hide();
ui->connectionReceiveWindow_l->hide();
ui->streamReceiveWindow->hide();
ui->streamReceiveWindow_l->hide();
}
ui->disableMtuDiscovery->hide();
ui->connectionReceiveWindow->hide();
ui->connectionReceiveWindow_l->hide();
ui->streamReceiveWindow->hide();
ui->streamReceiveWindow_l->hide();
}
} else if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_TUIC) {
ui->hopPort->hide();
@@ -107,9 +104,7 @@ void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
ui->streamReceiveWindow_l->hide();
ui->connectionReceiveWindow->hide();
ui->connectionReceiveWindow_l->hide();
if (!IS_NEKO_BOX) {
ui->uos->hide();
}
ui->uos->hide();
}
}

View File

@@ -7,7 +7,7 @@
EditShadowSocks::EditShadowSocks(QWidget *parent) : QWidget(parent),
ui(new Ui::EditShadowSocks) {
ui->setupUi(this);
ui->method->addItems(IS_NEKO_BOX ? Preset::SingBox::ShadowsocksMethods : Preset::Xray::ShadowsocksMethods);
ui->method->addItems(Preset::SingBox::ShadowsocksMethods);
}
EditShadowSocks::~EditShadowSocks() {

View File

@@ -23,7 +23,7 @@ void EditTrojanVLESS::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
ui->flow_l->hide();
}
ui->password->setText(bean->password);
ui->flow->addItems(IS_NEKO_BOX ? Preset::SingBox::Flows : Preset::Xray::Flows);
ui->flow->addItems(Preset::SingBox::Flows);
ui->flow->setCurrentText(bean->flow);
}

View File

@@ -91,18 +91,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
}
}
// software_name
if (IS_NEKO_BOX) {
software_name = "NekoBox";
software_core_name = "sing-box";
// replace default values
if (NekoGui::dataStore->log_level == "warning") NekoGui::dataStore->log_level = "info";
if (NekoGui::dataStore->mux_protocol.isEmpty()) NekoGui::dataStore->mux_protocol = "h2mux";
//
if (QDir("dashboard").count() == 0) {
QDir().mkdir("dashboard");
QFile::copy(":/neko/dashboard-notice.html", "dashboard/index.html");
}
if (QDir("dashboard").count() == 0) {
QDir().mkdir("dashboard");
QFile::copy(":/neko/dashboard-notice.html", "dashboard/index.html");
}
// top bar
@@ -398,10 +389,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
if (NekoGui::dataStore->core_port <= 0) NekoGui::dataStore->core_port = 19810;
auto core_path = QApplication::applicationDirPath() + "/";
core_path += IS_NEKO_BOX ? "nekobox_core" : "nekoray_core";
core_path += "nekobox_core";
QStringList args;
args.push_back(IS_NEKO_BOX ? "nekobox" : "nekoray");
args.push_back("nekobox");
args.push_back("-port");
args.push_back(Int2String(NekoGui::dataStore->core_port));
if (NekoGui::dataStore->flag_debug) args.push_back("-debug");
@@ -726,20 +717,8 @@ void MainWindow::on_menu_exit_triggered() {
void MainWindow::neko_set_spmode_system_proxy(bool enable, bool save) {
if (enable != NekoGui::dataStore->spmode_system_proxy) {
if (enable) {
#if defined(Q_OS_WIN)
if (!IS_NEKO_BOX && !IsValidPort(NekoGui::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);
if (btn == 1) {
on_menu_basic_settings_triggered();
}
return;
}
#endif
auto socks_port = NekoGui::dataStore->inbound_socks_port;
auto http_port = NekoGui::dataStore->inbound_http_port;
if (IS_NEKO_BOX) http_port = socks_port;
auto http_port = NekoGui::dataStore->inbound_socks_port;
SetSystemProxy(http_port, socks_port);
} else {
ClearSystemProxy();
@@ -761,7 +740,7 @@ void MainWindow::neko_set_spmode_system_proxy(bool enable, bool save) {
void MainWindow::neko_set_spmode_vpn(bool enable, bool save) {
if (enable != NekoGui::dataStore->spmode_vpn) {
if (enable) {
if (IS_NEKO_BOX_INTERNAL_TUN) {
if (NekoGui::dataStore->vpn_internal_tun) {
bool requestPermission = !NekoGui::IsAdmin();
if (requestPermission) {
#ifdef Q_OS_LINUX
@@ -799,7 +778,7 @@ void MainWindow::neko_set_spmode_vpn(bool enable, bool save) {
}
}
} else {
if (IS_NEKO_BOX_INTERNAL_TUN) {
if (NekoGui::dataStore->vpn_internal_tun) {
// current core is sing-box
} else {
if (!StopVPNProcess()) {
@@ -820,7 +799,7 @@ void MainWindow::neko_set_spmode_vpn(bool enable, bool save) {
NekoGui::dataStore->spmode_vpn = enable;
refresh_status();
if (IS_NEKO_BOX_INTERNAL_TUN && NekoGui::dataStore->started_id >= 0) neko_start(NekoGui::dataStore->started_id);
if (NekoGui::dataStore->vpn_internal_tun && NekoGui::dataStore->started_id >= 0) neko_start(NekoGui::dataStore->started_id);
}
void MainWindow::refresh_status(const QString &traffic_update) {
@@ -858,13 +837,8 @@ void MainWindow::refresh_status(const QString &traffic_update) {
ui->label_running->setText(txt);
}
//
auto display_http = tr("None");
if (IsValidPort(NekoGui::dataStore->inbound_http_port)) {
display_http = DisplayAddress(NekoGui::dataStore->inbound_address, NekoGui::dataStore->inbound_http_port);
}
auto display_socks = DisplayAddress(NekoGui::dataStore->inbound_address, NekoGui::dataStore->inbound_socks_port);
auto inbound_txt = QString("Socks: %1\nHTTP: %2").arg(display_socks, display_http);
if (IS_NEKO_BOX) inbound_txt = QString("Mixed: %1").arg(display_socks);
auto inbound_txt = QString("Mixed: %1").arg(display_socks);
ui->label_inbound->setText(inbound_txt);
//
ui->checkBox_VPN->setChecked(NekoGui::dataStore->spmode_vpn);