wip: hysteria2

仅通过编译不代表能用

Co-authored-by: xchacha20-poly1305 <139959885+xchacha20-poly1305@users.noreply.github.com>
This commit is contained in:
HystericalDragon
2023-09-02 11:50:09 +08:00
committed by arm64v8a
parent ff3696772c
commit aad4063ef7
10 changed files with 154 additions and 17 deletions

View File

@@ -48,6 +48,7 @@ https://matsuridayo.github.io
* TUIC ( sing-box ) * TUIC ( sing-box )
* NaïveProxy ( Custom Core ) * NaïveProxy ( Custom Core )
* Hysteria ( Custom Core or sing-box ) * Hysteria ( Custom Core or sing-box )
* Hysteria2 ( Custom Core or sing-box )
* Custom Outbound * Custom Outbound
* Custom Config * Custom Config
* Custom Core * Custom Core

View File

@@ -39,6 +39,7 @@ https://matsuridayo.github.io
* Trojan * Trojan
* NaïveProxy ( Custom Core ) * NaïveProxy ( Custom Core )
* Hysteria ( Custom Core or sing-box ) * Hysteria ( Custom Core or sing-box )
* Hysteria2 ( Custom Core or sing-box )
* Custom Outbound * Custom Outbound
* Custom Core * Custom Core

View File

@@ -186,6 +186,8 @@ namespace NekoGui {
bean = new NekoGui_fmt::NaiveBean(); bean = new NekoGui_fmt::NaiveBean();
} else if (type == "hysteria") { } else if (type == "hysteria") {
bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_Hysteria); bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_Hysteria);
} else if (type == "hysteria2" ) {
bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_Hysteria2);
} else if (type == "tuic") { } else if (type == "tuic") {
bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_TUIC); bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_TUIC);
} else if (type == "custom") { } else if (type == "custom") {

View File

@@ -199,13 +199,25 @@ namespace NekoGui_fmt {
if (!hopPort.trimmed().isEmpty()) outbound["hop_ports"] = hopPort; if (!hopPort.trimmed().isEmpty()) outbound["hop_ports"] = hopPort;
if (authPayloadType == hysteria_auth_base64) outbound["auth"] = authPayload; if (authPayloadType == hysteria_auth_base64) outbound["auth"] = authPayload;
if (authPayloadType == hysteria_auth_string) outbound["auth_str"] = authPayload; if (authPayloadType == hysteria_auth_string) outbound["auth_str"] = authPayload;
} else if (proxy_type == proxy_Hysteria2) {
outbound["type"] = "hysteria2";
outbound["password"] = authPayload;
if (uploadMbps > 0) outbound["up_mbps"] = uploadMbps;
if (downloadMbps > 0) outbound["down_mbps"] = downloadMbps;
if (!obfsPassword.isEmpty()) {
outbound["obfs"] = QJsonObject{
{"type", "salamander"},
{"password", obfsPassword},
};
}
} else if (proxy_type == proxy_TUIC) { } else if (proxy_type == proxy_TUIC) {
outbound["type"] = "tuic"; outbound["type"] = "tuic";
outbound["uuid"] = uuid; outbound["uuid"] = uuid;
outbound["password"] = password; outbound["password"] = password;
outbound["congestion_control"] = congestionControl; outbound["congestion_control"] = congestionControl;
if (uos) { if (uos) {
outbound["udp_over_stream"]= true; outbound["udp_over_stream"] = true;
} else { } else {
outbound["udp_relay_mode"] = udpRelayMode; outbound["udp_relay_mode"] = udpRelayMode;
} }

View File

@@ -50,6 +50,16 @@ namespace NekoGui_fmt {
return 1; return 1;
}; };
auto hysteria2Core = [=] {
if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn || !hopPort.trimmed().isEmpty()) {
return 1;
}
return 2;
}
return 1;
};
auto tuicCore = [=] { auto tuicCore = [=] {
if (isFirstProfile) { if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn) { if (NekoGui::dataStore->spmode_vpn) {
@@ -70,6 +80,8 @@ namespace NekoGui_fmt {
} }
} else if (proxy_type == proxy_TUIC) { } else if (proxy_type == proxy_TUIC) {
return tuicCore(); return tuicCore();
} else if (proxy_type == proxy_Hysteria2) {
return hysteria2Core();
} else { } else {
return hysteriaCore(); return hysteriaCore();
} }
@@ -162,6 +174,78 @@ namespace NekoGui_fmt {
result.arguments = QStringList{"-c", TempFile}; result.arguments = QStringList{"-c", TempFile};
return result; return result;
} else if (proxy_type == proxy_Hysteria2) {
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("hysteria2")};
QJsonObject config;
auto server = serverAddress;
if (!hopPort.trimmed().isEmpty()) {
server = WrapIPV6Host(server) + ":" + hopPort;
} else {
server = WrapIPV6Host(server) + ":" + Int2String(serverPort);
}
QJsonObject transport;
transport["type"] = "udp";
transport["udp"] = QJsonObject{
{"hopInterval", hopInterval},
};
config["transport"] = transport;
config["server"] = server;
config["socks5"] = QJsonObject{
{"listen", "127.0.0.1:" + Int2String(socks_port)},
{"disableUDP", false},
};
if (username.isEmpty()) {
config["auth"] = authPayload;
} else {
config["auth"] = username + ":" + authPayload;
}
QJsonObject bandwidth;
if (uploadMbps > 0) bandwidth["up"] = Int2String(uploadMbps) + " mbps";
if (downloadMbps > 0) bandwidth["down"] = Int2String(downloadMbps) + " mbps";
config["bandwidth"] = bandwidth;
QJsonObject quic;
if (streamReceiveWindow > 0) quic["initStreamReceiveWindow"] = streamReceiveWindow;
if (connectionReceiveWindow > 0) quic["initConnReceiveWindow"] = connectionReceiveWindow;
if (disableMtuDiscovery) quic["disablePathMTUDiscovery"] = true;
config["fastopen"] = true;
config["lazy"] = true;
if (!obfsPassword.isEmpty()) {
QJsonObject obfs;
obfs["type"] = "salamander";
obfs["salamander"] = QJsonObject{
{"password", obfsPassword},
};
config["obfs"] = obfs;
}
QJsonObject tls;
auto sniGen = sni;
if (sni.isEmpty() && !IsIpAddress(serverAddress)) sniGen = serverAddress;
tls["sni"] = sniGen;
if (allowInsecure) tls["insecure"] = true;
if (!caText.trimmed().isEmpty()) {
WriteTempFile("hysteria2_" + GetRandomString(10) + ".crt", caText.toUtf8());
QJsonArray certificate;
certificate.append(TempFile);
tls["certificates"] = certificate;
}
config["tls"] = tls;
result.config_export = QJsonObject2QString(config, false);
WriteTempFile("hysteria2_" + GetRandomString(10) + ".json", result.config_export.toUtf8());
result.arguments = QStringList{"-c", TempFile};
return result;
} else { // Hysteria } else { // Hysteria
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("hysteria")}; ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("hysteria")};

View File

@@ -7,6 +7,7 @@ namespace NekoGui_fmt {
public: public:
static constexpr int proxy_Hysteria = 0; static constexpr int proxy_Hysteria = 0;
static constexpr int proxy_TUIC = 1; static constexpr int proxy_TUIC = 1;
static constexpr int proxy_Hysteria2 = 3;
int proxy_type = proxy_Hysteria; int proxy_type = proxy_Hysteria;
// Hysteria // Hysteria
@@ -34,6 +35,9 @@ namespace NekoGui_fmt {
int hopInterval = 10; int hopInterval = 10;
QString hopPort = ""; QString hopPort = "";
// Hysteria 2 (Something same as hy1)
QString username = "";
// TUIC // TUIC
QString uuid = ""; QString uuid = "";
@@ -54,9 +58,7 @@ namespace NekoGui_fmt {
explicit QUICBean(int _proxy_type) : AbstractBean(0) { explicit QUICBean(int _proxy_type) : AbstractBean(0) {
proxy_type = _proxy_type; proxy_type = _proxy_type;
if (proxy_type == proxy_Hysteria) { if (proxy_type == proxy_Hysteria || proxy_type == proxy_Hysteria2) {
_add(new configItem("protocol", &hyProtocol, itemType::integer));
_add(new configItem("authPayloadType", &authPayloadType, itemType::integer));
_add(new configItem("authPayload", &authPayload, itemType::string)); _add(new configItem("authPayload", &authPayload, itemType::string));
_add(new configItem("obfsPassword", &obfsPassword, itemType::string)); _add(new configItem("obfsPassword", &obfsPassword, itemType::string));
_add(new configItem("uploadMbps", &uploadMbps, itemType::integer)); _add(new configItem("uploadMbps", &uploadMbps, itemType::integer));
@@ -66,6 +68,13 @@ namespace NekoGui_fmt {
_add(new configItem("disableMtuDiscovery", &disableMtuDiscovery, itemType::boolean)); _add(new configItem("disableMtuDiscovery", &disableMtuDiscovery, itemType::boolean));
_add(new configItem("hopInterval", &hopInterval, itemType::integer)); _add(new configItem("hopInterval", &hopInterval, itemType::integer));
_add(new configItem("hopPort", &hopPort, itemType::string)); _add(new configItem("hopPort", &hopPort, itemType::string));
if (proxy_type == proxy_Hysteria2) {
_add(new configItem("authPayloadType", &authPayloadType, itemType::integer));
_add(new configItem("protocol", &hyProtocol, itemType::integer));
} else {
_add(new configItem("username", &username, itemType::string));
}
} else if (proxy_type == proxy_TUIC) { } else if (proxy_type == proxy_TUIC) {
_add(new configItem("uuid", &uuid, itemType::string)); _add(new configItem("uuid", &uuid, itemType::string));
_add(new configItem("password", &password, itemType::string)); _add(new configItem("password", &password, itemType::string));

View File

@@ -170,6 +170,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
CACHE.extraCore = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map); CACHE.extraCore = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map);
if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", ""); if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", "");
if (!CACHE.extraCore.contains("hysteria")) CACHE.extraCore.insert("hysteria", ""); if (!CACHE.extraCore.contains("hysteria")) CACHE.extraCore.insert("hysteria", "");
if (!CACHE.extraCore.contains("hysteria2")) CACHE.extraCore.insert("hysteria2", "");
if (!CACHE.extraCore.contains("tuic")) CACHE.extraCore.insert("tuic", ""); if (!CACHE.extraCore.contains("tuic")) CACHE.extraCore.insert("tuic", "");
// //
auto extra_core_layout = ui->extra_core_box_scrollAreaWidgetContents->layout(); auto extra_core_layout = ui->extra_core_box_scrollAreaWidgetContents->layout();

View File

@@ -121,6 +121,7 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
LOAD_TYPE("vless") LOAD_TYPE("vless")
LOAD_TYPE("naive") LOAD_TYPE("naive")
LOAD_TYPE("hysteria") LOAD_TYPE("hysteria")
LOAD_TYPE("hysteria2")
LOAD_TYPE("tuic") LOAD_TYPE("tuic")
ui->type->addItem(tr("Custom (%1 outbound)").arg(software_core_name), "internal"); ui->type->addItem(tr("Custom (%1 outbound)").arg(software_core_name), "internal");
ui->type->addItem(tr("Custom (%1 config)").arg(software_core_name), "internal-full"); ui->type->addItem(tr("Custom (%1 config)").arg(software_core_name), "internal-full");
@@ -177,7 +178,7 @@ void DialogEditProfile::typeSelected(const QString &newType) {
auto _innerWidget = new EditNaive(this); auto _innerWidget = new EditNaive(this);
innerWidget = _innerWidget; innerWidget = _innerWidget;
innerEditor = _innerWidget; innerEditor = _innerWidget;
} else if (type == "hysteria" || type == "tuic") { } else if (type == "hysteria" || type == "hysteria2" || type == "tuic") {
auto _innerWidget = new EditQUIC(this); auto _innerWidget = new EditQUIC(this);
innerWidget = _innerWidget; innerWidget = _innerWidget;
innerEditor = _innerWidget; innerEditor = _innerWidget;

View File

@@ -19,15 +19,13 @@ void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
this->ent = _ent; this->ent = _ent;
auto bean = this->ent->QUICBean(); auto bean = this->ent->QUICBean();
if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_Hysteria) { if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_Hysteria || bean->proxy_type == NekoGui_fmt::QUICBean::proxy_Hysteria2) {
P_LOAD_STRING(hopPort); P_LOAD_STRING(hopPort);
P_LOAD_INT(hopInterval); P_LOAD_INT(hopInterval);
P_LOAD_INT(uploadMbps); P_LOAD_INT(uploadMbps);
P_LOAD_INT(downloadMbps); P_LOAD_INT(downloadMbps);
P_LOAD_COMBO_INT(hyProtocol);
P_LOAD_BOOL(disableMtuDiscovery) P_LOAD_BOOL(disableMtuDiscovery)
P_LOAD_STRING(obfsPassword); P_LOAD_STRING(obfsPassword);
P_LOAD_COMBO_INT(authPayloadType);
P_LOAD_STRING(authPayload); P_LOAD_STRING(authPayload);
P_LOAD_INT(streamReceiveWindow); P_LOAD_INT(streamReceiveWindow);
P_LOAD_INT(connectionReceiveWindow); P_LOAD_INT(connectionReceiveWindow);
@@ -45,6 +43,21 @@ void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
ui->heartbeat->hide(); ui->heartbeat->hide();
ui->heartbeat_l->hide(); ui->heartbeat_l->hide();
ui->uos->hide(); ui->uos->hide();
if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_Hysteria) {
P_LOAD_COMBO_INT(hyProtocol);
P_LOAD_COMBO_INT(authPayloadType);
ui->username_l->hide();
ui->username->hide();
} else {
P_LOAD_STRING(username);
ui->hyProtocol->hide();
ui->hyProtocol_l->hide();
ui->hyProtocol->hide();
ui->hyProtocol_l->hide();
}
} else if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_TUIC) { } else if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_TUIC) {
P_LOAD_STRING(uuid); P_LOAD_STRING(uuid);
P_LOAD_STRING(password); P_LOAD_STRING(password);
@@ -104,6 +117,9 @@ bool EditQUIC::onEnd() {
P_SAVE_INT(streamReceiveWindow); P_SAVE_INT(streamReceiveWindow);
P_SAVE_INT(connectionReceiveWindow); P_SAVE_INT(connectionReceiveWindow);
// Hysteria2
P_SAVE_STRING(username);
// TUIC // TUIC
P_SAVE_STRING(uuid); P_SAVE_STRING(uuid);
P_SAVE_STRING(password); P_SAVE_STRING(password);

View File

@@ -166,23 +166,16 @@
</item> </item>
<item> <item>
<layout class="QGridLayout" name="obfuscation"> <layout class="QGridLayout" name="obfuscation">
<item row="1" column="1"> <item row="2" column="1">
<widget class="MyLineEdit" name="obfsPassword"/> <widget class="MyLineEdit" name="obfsPassword"/>
</item> </item>
<item row="1" column="0"> <item row="2" column="0">
<widget class="QLabel" name="obfsPassword_l"> <widget class="QLabel" name="obfsPassword_l">
<property name="text"> <property name="text">
<string>Obfs Password</string> <string>Obfs Password</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0">
<widget class="QLabel" name="hyProtocol_l">
<property name="text">
<string>Protocol</string>
</property>
</widget>
</item>
<item row="0" column="1"> <item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item> <item>
@@ -219,6 +212,23 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="0" column="0">
<widget class="QLabel" name="hyProtocol_l">
<property name="text">
<string>Protocol</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="username_l">
<property name="text">
<string>Username</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="MyLineEdit" name="username"/>
</item>
</layout> </layout>
</item> </item>
<item> <item>