mirror of
https://github.com/Mahdi-zarei/nekoray.git
synced 2025-12-19 13:42:51 +08:00
lots of changes, will clarify later if works
This commit is contained in:
parent
773f07169b
commit
971e56937b
23
.github/workflows/build-qv2ray-cmake.yml
vendored
23
.github/workflows/build-qv2ray-cmake.yml
vendored
@ -25,25 +25,24 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checking out sources
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4.1.4
|
||||
- name: Go Status
|
||||
run: git ls-files go | xargs cat | sha1sum > go_status
|
||||
- name: Cache Common Download
|
||||
id: cache-common
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4.0.2
|
||||
with:
|
||||
path: artifacts.tgz
|
||||
key: CommonCache-${{ matrix.cross_os }}-${{ matrix.cross_arch }}-${{ hashFiles('libs/*.sh', 'go_status', '*.txt') }}
|
||||
- name: Install Golang
|
||||
if: steps.cache-common.outputs.cache-hit != 'true'
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5.0.0
|
||||
with:
|
||||
go-version: ^1.21
|
||||
go-version: ^1.22
|
||||
- name: Build golang parts
|
||||
if: steps.cache-common.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
[ ${{ matrix.cross_os }} == public_res ] || ./libs/get_source.sh
|
||||
[ ${{ matrix.cross_os }} == public_res ] || GOOS=${{ matrix.cross_os }} GOARCH=${{ matrix.cross_arch }} ./libs/build_go.sh
|
||||
[ ${{ matrix.cross_os }} == public_res ] || exit 0
|
||||
./libs/build_public_res.sh
|
||||
@ -51,7 +50,7 @@ jobs:
|
||||
if: steps.cache-common.outputs.cache-hit != 'true'
|
||||
run: tar czvf artifacts.tgz ./deployment
|
||||
- name: Uploading Artifact
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@v4.3.3
|
||||
with:
|
||||
name: NekoRay-${{ github.sha }}-Common-${{ matrix.cross_os }}-${{ matrix.cross_arch }}
|
||||
path: artifacts.tgz
|
||||
@ -72,7 +71,7 @@ jobs:
|
||||
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
|
||||
steps:
|
||||
- name: Checking out sources
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4.1.4
|
||||
with:
|
||||
submodules: "recursive"
|
||||
- name: Install MSVC compiler
|
||||
@ -94,7 +93,7 @@ jobs:
|
||||
uses: seanmiddleditch/gha-setup-ninja@v3
|
||||
- name: Cache Download
|
||||
id: cache-deps
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4.0.2
|
||||
with:
|
||||
path: libs/deps
|
||||
key: DepsCache-${{ matrix.platform }}-${{ matrix.arch }}-${{ hashFiles('libs/build_deps_*.sh') }}-Qt${{ matrix.qt_version }}
|
||||
@ -141,7 +140,7 @@ jobs:
|
||||
shell: bash
|
||||
run: tar czvf artifacts.tgz ./deployment
|
||||
- name: Uploading Artifact
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@v4.3.3
|
||||
with:
|
||||
name: NekoRay-${{ github.sha }}-${{ matrix.platform }}-${{ matrix.arch }}-Qt${{ matrix.qt_version }}
|
||||
path: artifacts.tgz
|
||||
@ -154,9 +153,9 @@ jobs:
|
||||
- build-go
|
||||
steps:
|
||||
- name: Checking out sources
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4.1.4
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4.1.7
|
||||
with:
|
||||
path: download-artifact
|
||||
- name: Pack
|
||||
@ -205,7 +204,7 @@ jobs:
|
||||
rm -rf public_res
|
||||
rm -rf *.pdb
|
||||
- name: Uploading Artifact
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@v4.3.3
|
||||
with:
|
||||
name: Deployment-${{ github.sha }}
|
||||
path: deployment
|
||||
|
||||
18
.github/workflows/update-pkgbuild.yml
vendored
18
.github/workflows/update-pkgbuild.yml
vendored
@ -1,18 +0,0 @@
|
||||
name: AUR CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'LICENSE'
|
||||
- '!.github/workflows/**'
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: chitang233/aur-pkgbuild-builder@main
|
||||
with:
|
||||
deploy_key: ${{ secrets.DEPLOY_KEY }}
|
||||
package_name: 'nekoray-git'
|
||||
@ -166,7 +166,6 @@ set(PROJECT_SOURCES
|
||||
db/ConfigBuilder.cpp
|
||||
|
||||
fmt/AbstractBean.cpp
|
||||
fmt/Bean2CoreObj_ray.cpp
|
||||
fmt/Bean2CoreObj_box.cpp
|
||||
fmt/Bean2External.cpp
|
||||
fmt/Bean2Link.cpp
|
||||
|
||||
@ -66,11 +66,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
|
||||
@ -172,254 +168,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);
|
||||
@ -472,26 +220,16 @@ namespace NekoGui {
|
||||
if (IS_NEKO_BOX) {
|
||||
replaced["detour"] = tagOut;
|
||||
} else {
|
||||
replaced["proxySettings"] = QJsonObject{
|
||||
{"tag", tagOut},
|
||||
{"transportLayer", true},
|
||||
};
|
||||
status->result->error = "Xray is no longer supported";
|
||||
return {};
|
||||
}
|
||||
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
|
||||
@ -530,43 +268,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"},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -589,23 +304,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 {};
|
||||
@ -624,58 +327,41 @@ namespace NekoGui {
|
||||
status->result->outboundStats += ent->traffic_data;
|
||||
|
||||
// mux common
|
||||
auto needMux = ent->type == "vmess" || ent->type == "trojan" || ent->type == "vless";
|
||||
auto needMux = ent->type == "vmess" || ent->type == "trojan" || ent->type == "vless" || ent->type == "shadowsocks";
|
||||
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->multiplex_status == 0) {
|
||||
if (!dataStore->mux_default_on) needMux = false;
|
||||
} else if (stream->multiplex_status == 1) {
|
||||
needMux = true;
|
||||
} else if (stream->multiplex_status == 2) {
|
||||
if (stream->network == "grpc" || stream->network == "quic" || (stream->network == "http" && stream->security == "tls")) {
|
||||
needMux = false;
|
||||
}
|
||||
}
|
||||
|
||||
auto mux_state = ent->bean->mux_state;
|
||||
if (mux_state == 0) {
|
||||
if (!dataStore->mux_default_on) needMux = false;
|
||||
} else if (mux_state == 1) {
|
||||
needMux = true;
|
||||
} else if (mux_state == 2) {
|
||||
needMux = false;
|
||||
}
|
||||
|
||||
if (ent->type == "vless" && outbound["flow"] != "") {
|
||||
needMux = false;
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -735,7 +421,7 @@ namespace NekoGui {
|
||||
}
|
||||
|
||||
// tun-in
|
||||
if (IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
|
||||
if (dataStore->spmode_vpn && !status->forTest) {
|
||||
QJsonObject inboundObj;
|
||||
inboundObj["tag"] = "tun-in";
|
||||
inboundObj["type"] = "tun";
|
||||
@ -885,7 +571,7 @@ namespace NekoGui {
|
||||
};
|
||||
|
||||
// Fakedns
|
||||
if (dataStore->fake_dns && IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
|
||||
if (dataStore->fake_dns && dataStore->spmode_vpn && !status->forTest) {
|
||||
dnsServers += QJsonObject{
|
||||
{"tag", "dns-fake"},
|
||||
{"address", "fakeip"},
|
||||
@ -927,7 +613,7 @@ namespace NekoGui {
|
||||
}
|
||||
|
||||
// fakedns rule
|
||||
if (dataStore->fake_dns && IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
|
||||
if (dataStore->fake_dns && dataStore->spmode_vpn && !status->forTest) {
|
||||
dnsRules += QJsonObject{
|
||||
{"inbound", "tun-in"},
|
||||
{"server", "dns-fake"},
|
||||
@ -970,11 +656,6 @@ namespace NekoGui {
|
||||
add_rule_route(status->ipListDirect, true, "bypass");
|
||||
|
||||
// built-in rules
|
||||
status->routingRules += QJsonObject{
|
||||
{"network", "udp"},
|
||||
{"port", QJsonArray{135, 137, 138, 139, 5353}},
|
||||
{"outbound", "block"},
|
||||
};
|
||||
status->routingRules += QJsonObject{
|
||||
{"ip_cidr", QJsonArray{"224.0.0.0/3", "ff00::/8"}},
|
||||
{"outbound", "block"},
|
||||
@ -985,7 +666,7 @@ namespace NekoGui {
|
||||
};
|
||||
|
||||
// tun user rule
|
||||
if (IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) {
|
||||
if (dataStore->spmode_vpn && !status->forTest) {
|
||||
auto match_out = dataStore->vpn_rule_white ? "proxy" : "bypass";
|
||||
|
||||
QString process_name_rule = dataStore->vpn_rule_process.trimmed();
|
||||
@ -1025,7 +706,7 @@ namespace NekoGui {
|
||||
QJSONARRAY_ADD(routingRules, status->routingRules)
|
||||
auto routeObj = QJsonObject{
|
||||
{"rules", routingRules},
|
||||
{"auto_detect_interface", dataStore->spmode_vpn},
|
||||
{"auto_detect_interface", true},
|
||||
{
|
||||
"geoip",
|
||||
QJsonObject{
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -34,6 +34,7 @@ namespace NekoGui_fmt {
|
||||
|
||||
QString custom_config = "";
|
||||
QString custom_outbound = "";
|
||||
int mux_state = 0;
|
||||
|
||||
explicit AbstractBean(int version);
|
||||
|
||||
@ -59,8 +60,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 {}; };
|
||||
|
||||
@ -200,10 +200,6 @@ namespace NekoGui_fmt {
|
||||
outbound["up_mbps"] = uploadMbps;
|
||||
outbound["down_mbps"] = downloadMbps;
|
||||
|
||||
if (!hopPort.trimmed().isEmpty()) {
|
||||
outbound["hop_ports"] = hopPort;
|
||||
outbound["hop_interval"] = hopInterval;
|
||||
}
|
||||
if (authPayloadType == hysteria_auth_base64) outbound["auth"] = authPayload;
|
||||
if (authPayloadType == hysteria_auth_string) outbound["auth_str"] = authPayload;
|
||||
} else if (proxy_type == proxy_Hysteria2) {
|
||||
@ -211,11 +207,7 @@ namespace NekoGui_fmt {
|
||||
outbound["password"] = password;
|
||||
outbound["up_mbps"] = uploadMbps;
|
||||
outbound["down_mbps"] = downloadMbps;
|
||||
|
||||
if (!hopPort.trimmed().isEmpty()) {
|
||||
outbound["hop_ports"] = hopPort;
|
||||
outbound["hop_interval"] = hopInterval;
|
||||
}
|
||||
|
||||
if (!obfsPassword.isEmpty()) {
|
||||
outbound["obfs"] = QJsonObject{
|
||||
{"type", "salamander"},
|
||||
|
||||
@ -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
|
||||
@ -64,6 +64,13 @@ namespace NekoGui_fmt {
|
||||
}
|
||||
}
|
||||
|
||||
// mux
|
||||
if (mux_state == 1) {
|
||||
query.addQueryItem("mux", "true");
|
||||
} else if (mux_state == 2) {
|
||||
query.addQueryItem("mux", "false");
|
||||
}
|
||||
|
||||
// protocol
|
||||
if (proxy_type == proxy_VLESS) {
|
||||
if (!flow.isEmpty()) {
|
||||
@ -92,6 +99,20 @@ namespace NekoGui_fmt {
|
||||
if (!name.isEmpty()) url.setFragment(name);
|
||||
QUrlQuery q;
|
||||
if (!plugin.isEmpty()) q.addQueryItem("plugin", plugin);
|
||||
|
||||
// mux
|
||||
if (mux_state == 1) {
|
||||
q.addQueryItem("mux", "true");
|
||||
} else if (mux_state == 2) {
|
||||
q.addQueryItem("mux", "false");
|
||||
}
|
||||
// uot
|
||||
if (uot == 1) {
|
||||
q.addQueryItem("uot", "1");
|
||||
} else if (uot == 2) {
|
||||
q.addQueryItem("uot", "2");
|
||||
}
|
||||
|
||||
if (!q.isEmpty()) url.setQuery(q);
|
||||
//
|
||||
auto link = url.toString(QUrl::FullyEncoded);
|
||||
@ -164,6 +185,13 @@ namespace NekoGui_fmt {
|
||||
}
|
||||
}
|
||||
|
||||
// mux
|
||||
if (mux_state == 1) {
|
||||
query.addQueryItem("mux", "true");
|
||||
} else if (mux_state == 2) {
|
||||
query.addQueryItem("mux", "false");
|
||||
}
|
||||
|
||||
url.setQuery(query);
|
||||
return url.toString(QUrl::FullyEncoded);
|
||||
}
|
||||
@ -196,7 +224,6 @@ namespace NekoGui_fmt {
|
||||
if (authPayloadType == hysteria_auth_string) q.addQueryItem("auth", authPayload);
|
||||
if (hyProtocol == hysteria_protocol_facktcp) q.addQueryItem("protocol", "faketcp");
|
||||
if (hyProtocol == hysteria_protocol_wechat_video) q.addQueryItem("protocol", "wechat-video");
|
||||
if (!hopPort.trimmed().isEmpty()) q.addQueryItem("mport", hopPort);
|
||||
if (allowInsecure) q.addQueryItem("insecure", "1");
|
||||
if (!sni.isEmpty()) q.addQueryItem("peer", sni);
|
||||
if (!alpn.isEmpty()) q.addQueryItem("alpn", alpn);
|
||||
@ -235,7 +262,6 @@ namespace NekoGui_fmt {
|
||||
q.addQueryItem("obfs", "salamander");
|
||||
q.addQueryItem("obfs-password", obfsPassword);
|
||||
}
|
||||
if (!hopPort.trimmed().isEmpty()) q.addQueryItem("mport", hopPort);
|
||||
if (allowInsecure) q.addQueryItem("insecure", "1");
|
||||
if (!sni.isEmpty()) q.addQueryItem("sni", sni);
|
||||
if (!q.isEmpty()) url.setQuery(q);
|
||||
|
||||
@ -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
|
||||
@ -100,6 +100,14 @@ namespace NekoGui_fmt {
|
||||
}
|
||||
}
|
||||
|
||||
// mux
|
||||
auto mux_str = GetQueryValue(query, "mux", "");
|
||||
if (mux_str == "true") {
|
||||
mux_state = 1;
|
||||
} else if (mux_str == "false") {
|
||||
mux_state = 2;
|
||||
}
|
||||
|
||||
// protocol
|
||||
if (proxy_type == proxy_VLESS) {
|
||||
flow = GetQueryValue(query, "flow", "");
|
||||
@ -132,6 +140,13 @@ namespace NekoGui_fmt {
|
||||
|
||||
auto query = GetQuery(url);
|
||||
plugin = query.queryItemValue("plugin").replace("simple-obfs;", "obfs-local;");
|
||||
auto mux_str = GetQueryValue(query, "mux", "");
|
||||
if (mux_str == "true") {
|
||||
mux_state = 1;
|
||||
} else if (mux_str == "false") {
|
||||
mux_state = 2;
|
||||
}
|
||||
|
||||
} else {
|
||||
// v2rayN
|
||||
DECODE_V2RAY_N_1
|
||||
@ -210,6 +225,14 @@ namespace NekoGui_fmt {
|
||||
stream->utlsFingerprint = NekoGui::dataStore->utlsFingerprint;
|
||||
}
|
||||
|
||||
// mux
|
||||
auto mux_str = GetQueryValue(query, "mux", "");
|
||||
if (mux_str == "true") {
|
||||
mux_state = 1;
|
||||
} else if (mux_str == "false") {
|
||||
mux_state = 2;
|
||||
}
|
||||
|
||||
// type
|
||||
if (stream->network == "ws") {
|
||||
stream->path = GetQueryValue(query, "path", "");
|
||||
@ -263,7 +286,6 @@ namespace NekoGui_fmt {
|
||||
name = url.fragment(QUrl::FullyDecoded);
|
||||
serverAddress = url.host();
|
||||
serverPort = url.port();
|
||||
hopPort = query.queryItemValue("mport");
|
||||
obfsPassword = query.queryItemValue("obfsParam");
|
||||
allowInsecure = QStringList{"1", "true"}.contains(query.queryItemValue("insecure"));
|
||||
uploadMbps = query.queryItemValue("upmbps").toInt();
|
||||
@ -308,7 +330,6 @@ namespace NekoGui_fmt {
|
||||
name = url.fragment(QUrl::FullyDecoded);
|
||||
serverAddress = url.host();
|
||||
serverPort = url.port();
|
||||
hopPort = query.queryItemValue("mport");
|
||||
obfsPassword = query.queryItemValue("obfs-password");
|
||||
allowInsecure = QStringList{"1", "true"}.contains(query.queryItemValue("insecure"));
|
||||
|
||||
|
||||
@ -23,8 +23,6 @@ namespace NekoGui_fmt {
|
||||
|
||||
QString DisplayType() override { return "Shadowsocks"; };
|
||||
|
||||
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
|
||||
|
||||
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
|
||||
|
||||
bool TryParseLink(const QString &link);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -26,8 +26,6 @@ namespace NekoGui_fmt {
|
||||
QString reality_pbk = "";
|
||||
QString reality_sid = "";
|
||||
QString reality_spx = "";
|
||||
// multiplex
|
||||
int multiplex_status = 0;
|
||||
|
||||
V2rayStreamSettings() : JsonStore() {
|
||||
_add(new configItem("net", &network, itemType::string));
|
||||
@ -46,11 +44,8 @@ namespace NekoGui_fmt {
|
||||
_add(new configItem("pbk", &reality_pbk, itemType::string));
|
||||
_add(new configItem("sid", &reality_sid, itemType::string));
|
||||
_add(new configItem("spx", &reality_spx, itemType::string));
|
||||
_add(new configItem("mux_s", &multiplex_status, itemType::integer));
|
||||
}
|
||||
|
||||
QJsonObject BuildStreamSettingsV2Ray();
|
||||
|
||||
void BuildStreamSettingsSingBox(QJsonObject *outbound);
|
||||
};
|
||||
|
||||
|
||||
@ -21,8 +21,6 @@ namespace NekoGui_fmt {
|
||||
|
||||
QString DisplayType() override { return "VMess"; };
|
||||
|
||||
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
|
||||
|
||||
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
|
||||
|
||||
bool TryParseLink(const QString &link);
|
||||
|
||||
@ -23,15 +23,6 @@ pushd go/cmd/updater
|
||||
[ "$GOOS" == "linux" ] && mv $DEST/updater $DEST/launcher || true
|
||||
popd
|
||||
|
||||
#### Go: nekoray_core ####
|
||||
neko_common="github.com/matsuridayo/libneko/neko_common"
|
||||
pushd ../Xray-core
|
||||
Version_Xray=$(git log --pretty=format:'%h' -n 1)
|
||||
popd
|
||||
pushd go/cmd/nekoray_core
|
||||
go build -v -o $DEST -trimpath -ldflags "-w -s -X $neko_common.Version_v2ray=$Version_Xray -X $neko_common.Version_neko=$version_standalone"
|
||||
popd
|
||||
|
||||
#### Go: nekobox_core ####
|
||||
pushd go/cmd/nekobox_core
|
||||
go build -v -o $DEST -trimpath -ldflags "-w -s -X $neko_common.Version_neko=$version_standalone" -tags "with_clash_api,with_gvisor,with_quic,with_wireguard,with_utls,with_ech"
|
||||
|
||||
@ -18,7 +18,6 @@ namespace NekoGui {
|
||||
|
||||
namespace CoreType {
|
||||
enum CoreType {
|
||||
V2RAY,
|
||||
SING_BOX,
|
||||
};
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
// Switch core support
|
||||
|
||||
namespace NekoGui {
|
||||
inline int coreType = CoreType::V2RAY;
|
||||
inline int coreType = CoreType::SING_BOX;
|
||||
|
||||
QString FindCoreAsset(const QString &name);
|
||||
|
||||
|
||||
@ -164,19 +164,13 @@ int main(int argc, char* argv[]) {
|
||||
if (coreLoaded.isEmpty()) {
|
||||
NekoGui::coreType = -1;
|
||||
loadTranslate(QLocale().name());
|
||||
auto dialogFirstSetup = new DialogFirstSetup;
|
||||
dialogFirstSetup->exec();
|
||||
dialogFirstSetup->deleteLater();
|
||||
if (NekoGui::coreType < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
QDir().mkdir("groups");
|
||||
QFile file;
|
||||
file.setFileName("groups/coreType");
|
||||
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
|
||||
file.write(Int2String(NekoGui::coreType).toUtf8());
|
||||
file.close();
|
||||
}
|
||||
NekoGui::coreType = NekoGui::CoreType::SING_BOX;
|
||||
QDir().mkdir("groups");
|
||||
QFile file;
|
||||
file.setFileName("groups/coreType");
|
||||
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
|
||||
file.write(Int2String(NekoGui::coreType).toUtf8());
|
||||
file.close();
|
||||
} else {
|
||||
NekoGui::coreType = coreLoaded.toInt();
|
||||
}
|
||||
@ -200,9 +194,6 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
// Load dataStore
|
||||
switch (NekoGui::coreType) {
|
||||
case NekoGui::CoreType::V2RAY:
|
||||
NekoGui::dataStore->fn = "groups/nekoray.json";
|
||||
break;
|
||||
case NekoGui::CoreType::SING_BOX:
|
||||
NekoGui::dataStore->fn = "groups/nekobox.json";
|
||||
break;
|
||||
|
||||
@ -278,7 +278,7 @@ namespace NekoGui_sub {
|
||||
|
||||
// sing-mux
|
||||
auto smux = NodeChild(proxy, {"smux"});
|
||||
if (Node2Bool(smux["enabled"])) bean->stream->multiplex_status = 1;
|
||||
if (Node2Bool(smux["enabled"])) bean->mux_state = 1;
|
||||
} else if (type == "socks" || type == "http") {
|
||||
auto bean = ent->SocksHTTPBean();
|
||||
bean->username = Node2QString(proxy["username"]);
|
||||
@ -313,7 +313,7 @@ namespace NekoGui_sub {
|
||||
|
||||
// sing-mux
|
||||
auto smux = NodeChild(proxy, {"smux"});
|
||||
if (Node2Bool(smux["enabled"])) bean->stream->multiplex_status = 1;
|
||||
if (Node2Bool(smux["enabled"])) bean->mux_state = 1;
|
||||
|
||||
// opts
|
||||
auto ws = NodeChild(proxy, {"ws-opts", "ws-opt"});
|
||||
@ -358,7 +358,7 @@ namespace NekoGui_sub {
|
||||
|
||||
// sing-mux
|
||||
auto smux = NodeChild(proxy, {"smux"});
|
||||
if (Node2Bool(smux["enabled"])) bean->stream->multiplex_status = 1;
|
||||
if (Node2Bool(smux["enabled"])) bean->mux_state = 1;
|
||||
|
||||
// meta packet encoding
|
||||
if (Node2Bool(proxy["xudp"])) bean->stream->packet_encoding = "xudp";
|
||||
|
||||
@ -218,31 +218,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
||||
});
|
||||
|
||||
// switch core
|
||||
ui->switch_core_v2ray->setChecked(!IS_NEKO_BOX);
|
||||
ui->switch_core_sing_box->setChecked(IS_NEKO_BOX);
|
||||
auto switch_core_on_click = [=] {
|
||||
int neko_core_new;
|
||||
if (sender() == ui->switch_core_sing_box) {
|
||||
if (IS_NEKO_BOX) return;
|
||||
neko_core_new = NekoGui::CoreType::SING_BOX;
|
||||
} else {
|
||||
if (!IS_NEKO_BOX) return;
|
||||
neko_core_new = NekoGui::CoreType::V2RAY;
|
||||
}
|
||||
QString core_name_new = dynamic_cast<QRadioButton *>(sender())->text();
|
||||
if (QMessageBox::question(this, tr("Confirmation"),
|
||||
tr("Switching the core to %1, click \"Yes\" to complete the switch and the program will restart. This feature may be unstable, please do not switch frequently.")
|
||||
.arg(core_name_new)) == QMessageBox::StandardButton::Yes) {
|
||||
QFile file;
|
||||
file.setFileName("groups/coreType");
|
||||
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
|
||||
file.write(Int2String(neko_core_new).toUtf8());
|
||||
file.close();
|
||||
MW_dialog_message("", "RestartProgram");
|
||||
}
|
||||
};
|
||||
connect(ui->switch_core_v2ray, &QRadioButton::clicked, this, switch_core_on_click);
|
||||
connect(ui->switch_core_sing_box, &QRadioButton::clicked, this, switch_core_on_click);
|
||||
|
||||
// Mux
|
||||
D_LOAD_INT(mux_concurrency)
|
||||
|
||||
@ -13,10 +13,6 @@ DialogFirstSetup::~DialogFirstSetup() {
|
||||
|
||||
void DialogFirstSetup::onButtonClicked() {
|
||||
auto s = sender();
|
||||
if (s == ui->v2ray) {
|
||||
NekoGui::coreType = NekoGui::CoreType::V2RAY;
|
||||
} else if (s == ui->singbox) {
|
||||
NekoGui::coreType = NekoGui::CoreType::SING_BOX;
|
||||
}
|
||||
NekoGui::coreType = NekoGui::CoreType::SING_BOX;
|
||||
done(0);
|
||||
}
|
||||
|
||||
@ -236,7 +236,7 @@ void DialogEditProfile::typeSelected(const QString &newType) {
|
||||
ui->ws_early_data_length->setText(Int2String(stream->ws_early_data_length));
|
||||
ui->reality_pbk->setText(stream->reality_pbk);
|
||||
ui->reality_sid->setText(stream->reality_sid);
|
||||
ui->multiplex->setCurrentIndex(stream->multiplex_status);
|
||||
ui->multiplex->setCurrentIndex(ent->bean->mux_state);
|
||||
CACHE.certificate = stream->certificate;
|
||||
} else {
|
||||
ui->right_all_w->setVisible(false);
|
||||
@ -371,7 +371,7 @@ bool DialogEditProfile::onEnd() {
|
||||
stream->ws_early_data_length = ui->ws_early_data_length->text().toInt();
|
||||
stream->reality_pbk = ui->reality_pbk->text();
|
||||
stream->reality_sid = ui->reality_sid->text();
|
||||
stream->multiplex_status = ui->multiplex->currentIndex();
|
||||
ent->bean->mux_state = ui->multiplex->currentIndex();
|
||||
stream->certificate = CACHE.certificate;
|
||||
}
|
||||
|
||||
@ -515,7 +515,7 @@ void DialogEditProfile::do_apply_to_group(const std::shared_ptr<NekoGui::Group>
|
||||
};
|
||||
|
||||
if (key == ui->multiplex) {
|
||||
copyStream(&stream->multiplex_status);
|
||||
copyStream(&ent->bean->mux_state);
|
||||
} else if (key == ui->sni) {
|
||||
copyStream(&stream->sni);
|
||||
} else if (key == ui->alpn) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user