feat: direct external

This commit is contained in:
arm64v8a
2022-11-09 10:43:43 +09:00
parent 7c47a616e4
commit 0b3af33c64
12 changed files with 99 additions and 49 deletions

View File

@@ -325,6 +325,7 @@ namespace NekoRay {
bool muxApplied = false;
QString pastTag;
int pastExternalStat = 0;
int index = 0;
for (const auto &ent: ents) {
@@ -338,13 +339,15 @@ namespace NekoRay {
bool needGlobal = false;
// first profile set as global
if (index == ents.length() - 1) {
auto isFirstProfile = index == ents.length() - 1;
if (isFirstProfile) {
needGlobal = true;
tagOut = "g-" + Int2String(ent->id);
}
// last profile set as "proxy"
if (chainId == 0 && index == 0) {
needGlobal = false;
tagOut = "proxy";
}
@@ -357,7 +360,7 @@ namespace NekoRay {
if (index > 0) {
// chain rules: past
if (!ents[index - 1]->bean->NeedExternal()) {
if (pastExternalStat == 0) {
auto replaced = status->outbounds.last().toObject();
if (IS_NEKO_BOX) {
replaced["detour"] = tagOut;
@@ -385,7 +388,11 @@ namespace NekoRay {
// chain rules: this
auto mapping_port = MkPort();
if (ent->bean->NeedExternal()) {
auto thisExternalStat = ent->bean->NeedExternal(isFirstProfile,
dataStore->running_spmode == SystemProxyMode::VPN);
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"},
@@ -404,7 +411,7 @@ namespace NekoRay {
{"network", "tcp,udp"},}},};
}
// no chain rule and not outbound, so need to set to direct
if (index == ents.length() - 1) {
if (isFirstProfile) {
if (IS_NEKO_BOX) {
status->routingRules += QJsonObject{{"inbound", QJsonArray{tagOut + "-mapping"}},
{"outbound", "direct"},};
@@ -422,9 +429,9 @@ namespace NekoRay {
fmt::CoreObjOutboundBuildResult coreR;
fmt::ExternalBuildResult extR;
if (ent->bean->NeedExternal()) {
if (thisExternalStat > 0) {
auto ext_socks_port = MkPort();
extR = ent->bean->BuildExternal(mapping_port, ext_socks_port);
extR = ent->bean->BuildExternal(mapping_port, ext_socks_port, thisExternalStat);
if (extR.program.isEmpty()) {
status->result->error = QObject::tr("Core not found: %1").arg(ent->bean->DisplayType());
return {};
@@ -512,7 +519,7 @@ namespace NekoRay {
}
// Bypass Lookup for the first profile
if (index == ents.length() - 1 && !IsIpAddress(ent->bean->serverAddress)) {
if (isFirstProfile && !IsIpAddress(ent->bean->serverAddress)) {
if (dataStore->enhance_resolve_server_domain && !IS_NEKO_BOX) {
status->result->tryDomains += ent->bean->serverAddress;
} else {
@@ -522,6 +529,7 @@ namespace NekoRay {
status->outbounds += outbound;
pastTag = tagOut;
pastExternalStat = thisExternalStat;
index++;
}

View File

@@ -47,13 +47,13 @@ namespace NekoRay::fmt {
//
virtual bool NeedExternal() { return false; };
virtual int NeedExternal(bool isFirstProfile, bool isVPN) { return 0; };
virtual CoreObjOutboundBuildResult BuildCoreObjV2Ray() { return {}; };
virtual CoreObjOutboundBuildResult BuildCoreObjSingBox() { return {}; };
virtual ExternalBuildResult BuildExternal(int mapping_port, int socks_port) { return {}; };
virtual ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) { return {}; };
virtual QString ToShareLink() { return {}; };

View File

@@ -1,5 +1,7 @@
#include "db/ProxyEntity.hpp"
#include "fmt/includes.h"
#include "NaiveBean.hpp"
#include <QFile>
#include <QDir>
@@ -19,13 +21,37 @@ f.close(); \
auto TempFile = QFileInfo(f).absoluteFilePath();
namespace NekoRay::fmt {
ExternalBuildResult NaiveBean::BuildExternal(int mapping_port, int socks_port) {
// 0: no external
// 1: Mapping External
// 2: Direct External
int NaiveBean::NeedExternal(bool isFirstProfile, bool isVPN) {
if (isFirstProfile && !isVPN) {
return 2;
}
return 1;
}
int CustomBean::NeedExternal(bool isFirstProfile, bool isVPN) {
if (core == "internal") return 0;
if (IS_NEKO_BOX && core == "hysteria") return 0;
if (core == "hysteria") {
if (isFirstProfile && !isVPN) {
return 2;
}
}
return 1;
}
ExternalBuildResult NaiveBean::BuildExternal(int mapping_port, int socks_port, int external_stat) {
ExternalBuildResult result{dataStore->extraCore->Get("naive")};
auto is_export = mapping_port == 114514;
auto is_direct = external_stat == 2;
auto domain_address = sni.isEmpty() ? serverAddress : sni;
auto connect_address = is_export ? serverAddress : "127.0.0.1";
auto connect_port = is_export ? serverPort : mapping_port;
auto connect_address = is_direct ? serverAddress : "127.0.0.1";
auto connect_port = is_direct ? serverPort : mapping_port;
domain_address = WrapIPV6Host(domain_address);
connect_address = WrapIPV6Host(connect_address);
result.arguments += "--log";
result.arguments += "--listen=socks://127.0.0.1:" + Int2String(socks_port);
@@ -47,7 +73,7 @@ namespace NekoRay::fmt {
return result;
}
ExternalBuildResult CustomBean::BuildExternal(int mapping_port, int socks_port) {
ExternalBuildResult CustomBean::BuildExternal(int mapping_port, int socks_port, int external_stat) {
ExternalBuildResult result{dataStore->extraCore->Get(core)};
result.arguments = command; // TODO split?
@@ -75,6 +101,15 @@ namespace NekoRay::fmt {
suffix = ".json";
}
// known core direct out
if (external_stat == 2) {
if (core == "hysteria") {
config = config.replace(QString("\"127.0.0.1:%1\"").arg(mapping_port),
"\"" + DisplayAddress() + "\"");
}
}
// write config
WriteTempFile("custom_" + GetRandomString(10) + suffix, config.toUtf8());
for (int i = 0; i < result.arguments.count(); i++) {
result.arguments[i] = result.arguments[i].replace("%config%", TempFile);

View File

@@ -25,7 +25,7 @@ namespace NekoRay::fmt {
return core;
};
QString DisplayCoreType() override { return NeedExternal() ? core : software_core_name; };
QString DisplayCoreType() override { return NeedExternal(false, false) ? core : software_core_name; };
QString DisplayAddress() override {
if (core == "internal") {
@@ -39,13 +39,9 @@ namespace NekoRay::fmt {
return AbstractBean::DisplayAddress();
};
bool NeedExternal() override {
if (core == "internal") return false;
if (IS_NEKO_BOX && core == "hysteria") return false;
return true;
};
int NeedExternal(bool isFirstProfile, bool isVPN) override;
ExternalBuildResult BuildExternal(int mapping_port, int socks_port) override;
ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;

View File

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

View File

@@ -35,7 +35,7 @@ func (s *server) Start(ctx context.Context, in *gen.LoadConfigReq) (out *gen.Err
}()
if neko_common.Debug {
logrus.Println("Start:", in)
logrus.Println("Start:", in.CoreConfig, in.TryDomains)
}
if instance != nil {

View File

@@ -41,7 +41,7 @@ namespace NekoRay {
_add(new configItem("remember_enable", &remember_enable, itemType::boolean));
_add(new configItem("start_minimal", &start_minimal, itemType::boolean));
_add(new configItem("language", &language, itemType::integer));
_add(new configItem("spmode", &system_proxy_mode, itemType::integer));
_add(new configItem("spmode", &remember_spmode, itemType::integer));
_add(new configItem("insecure_hint", &insecure_hint, itemType::boolean));
_add(new configItem("skip_cert", &skip_cert, itemType::boolean));
_add(new configItem("hk_mw", &hotkey_mainwindow, itemType::string));

View File

@@ -45,6 +45,8 @@ namespace NekoRay {
int started_id = -1919;
bool core_running = false;
bool core_prepare_exit = false;
int running_spmode = NekoRay::SystemProxyMode::DISABLE;
bool need_keep_vpn_off = false;
Routing *routing = new Routing;
int imported_count = 0;
@@ -82,7 +84,7 @@ namespace NekoRay {
bool skip_cert = false;
// Remember
int system_proxy_mode = NekoRay::SystemProxyMode::DISABLE;
int remember_spmode = NekoRay::SystemProxyMode::DISABLE;
int remember_id = -1919;
bool remember_enable = false;
bool start_minimal = false;

View File

@@ -1185,6 +1185,10 @@ End: %2</source>
<source>Not Running</source>
<translation></translation>
</message>
<message>
<source>Current server is incompatible with VPN. Please stop the server first, enable VPN mode, and then restart.</source>
<translation> VPN VPN </translation>
</message>
</context>
<context>
<name>ProxyItem</name>

View File

@@ -338,9 +338,10 @@ MainWindow::MainWindow(QWidget *parent)
neko_set_spmode(checked ? NekoRay::SystemProxyMode::SYSTEM_PROXY : NekoRay::SystemProxyMode::DISABLE);
});
connect(ui->menu_spmode, &QMenu::aboutToShow, this, [=]() {
ui->menu_spmode_disabled->setChecked(title_spmode == NekoRay::SystemProxyMode::DISABLE);
ui->menu_spmode_system_proxy->setChecked(title_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY);
ui->menu_spmode_vpn->setChecked(title_spmode == NekoRay::SystemProxyMode::VPN);
ui->menu_spmode_disabled->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::DISABLE);
ui->menu_spmode_system_proxy->setChecked(
NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY);
ui->menu_spmode_vpn->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN);
});
connect(ui->menu_spmode_system_proxy, &QAction::triggered, this,
[=]() { neko_set_spmode(NekoRay::SystemProxyMode::SYSTEM_PROXY); });
@@ -392,8 +393,8 @@ MainWindow::MainWindow(QWidget *parent)
// Start last
if (NekoRay::dataStore->remember_enable) {
if (NekoRay::dataStore->system_proxy_mode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
neko_set_spmode(NekoRay::dataStore->system_proxy_mode, false);
if (NekoRay::dataStore->remember_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
neko_set_spmode(NekoRay::dataStore->remember_spmode, false);
}
if (NekoRay::dataStore->remember_id >= 0) {
runOnUiThread([=] { neko_start(NekoRay::dataStore->remember_id); });
@@ -465,7 +466,7 @@ void MainWindow::dialog_message_impl(const QString &sender, const QString &info)
auto changed = NekoRay::dataStore->Save();
if (info.contains("RouteChanged")) changed = true;
refresh_proxy_list();
if (info.contains("VPNChanged") && title_spmode == NekoRay::SystemProxyMode::VPN) {
if (info.contains("VPNChanged") && NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) {
MessageBoxWarning(tr("VPN settings changed"), tr("Restart VPN to take effect."));
} else if (changed && NekoRay::dataStore->started_id >= 0 &&
QMessageBox::question(GetMessageBoxParent(), tr("Confirmation"),
@@ -554,7 +555,7 @@ void MainWindow::on_commitDataRequest() {
void MainWindow::on_menu_exit_triggered() {
neko_set_spmode(NekoRay::SystemProxyMode::DISABLE, false);
if (title_spmode == NekoRay::SystemProxyMode::VPN) return;
if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) return;
RegisterHotkey(true);
//
on_commitDataRequest();
@@ -574,16 +575,17 @@ void MainWindow::on_menu_exit_triggered() {
qApp->quit();
}
#define neko_set_spmode_FAILED refresh_status(); return;
void MainWindow::neko_set_spmode(int mode, bool save) {
if (mode != title_spmode) {
if (mode != NekoRay::dataStore->running_spmode) {
// DISABLE
if (title_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
ClearSystemProxy();
} else if (title_spmode == NekoRay::SystemProxyMode::VPN) {
} else if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) {
if (!StopVPNProcess()) {
refresh_status();
return;
neko_set_spmode_FAILED
}
}
@@ -609,19 +611,22 @@ void MainWindow::neko_set_spmode(int mode, bool save) {
}
SetSystemProxy(http_port, socks_port);
} else if (mode == NekoRay::SystemProxyMode::VPN) {
if (NekoRay::dataStore->need_keep_vpn_off) {
MessageBoxWarning(software_name, tr("Current server is incompatible with VPN. Please stop the server first, enable VPN mode, and then restart."));
neko_set_spmode_FAILED
}
if (!StartVPNProcess()) {
refresh_status();
return;
neko_set_spmode_FAILED
}
}
}
if (save) {
NekoRay::dataStore->system_proxy_mode = mode;
NekoRay::dataStore->remember_spmode = mode;
NekoRay::dataStore->Save();
}
title_spmode = mode;
NekoRay::dataStore->running_spmode = mode;
refresh_status();
}
@@ -654,17 +659,17 @@ void MainWindow::refresh_status(const QString &traffic_update) {
if (IS_NEKO_BOX) inbound_txt = QString("Mixed: %1").arg(display_socks);
ui->label_inbound->setText(inbound_txt);
//
ui->checkBox_VPN->setChecked(title_spmode == NekoRay::SystemProxyMode::VPN);
ui->checkBox_SystemProxy->setChecked(title_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY);
ui->checkBox_VPN->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN);
ui->checkBox_SystemProxy->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY);
if (select_mode) ui->label_running->setText("[" + tr("Select") + "]");
auto make_title = [=](bool isTray) {
QStringList tt;
if (select_mode) tt << "[" + tr("Select") + "]";
if (!title_error.isEmpty()) tt << "[" + title_error + "]";
if (title_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
tt << "[" + tr("System Proxy") + "]";
} else if (title_spmode == NekoRay::SystemProxyMode::VPN) {
} else if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) {
tt << "[" + tr("VPN Mode") + "]";
}
tt << software_name;
@@ -677,9 +682,9 @@ void MainWindow::refresh_status(const QString &traffic_update) {
};
auto icon_status_new = TrayIcon::NONE;
if (title_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
icon_status_new = TrayIcon::SYSTEM_PROXY;
} else if (title_spmode == NekoRay::SystemProxyMode::VPN) {
} else if (NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) {
icon_status_new = TrayIcon::VPN;
} else if (!running.isNull()) {
icon_status_new = TrayIcon::RUNNING;

View File

@@ -139,7 +139,6 @@ private:
QTextDocument *qvLogDocument = new QTextDocument(this);
//
QString title_error;
int title_spmode = NekoRay::SystemProxyMode::DISABLE;
int icon_status = -1;
QSharedPointer<NekoRay::ProxyEntity> running;
QString traffic_update_cache;

View File

@@ -292,6 +292,7 @@ void MainWindow::neko_stop(bool crash) {
#endif
NekoRay::dataStore->UpdateStartedId(-1919);
NekoRay::dataStore->need_keep_vpn_off = false;
running = nullptr;
refresh_status();
refresh_proxy_list(id);