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 )
* NaïveProxy ( Custom Core )
* Hysteria ( Custom Core or sing-box )
* Hysteria2 ( Custom Core or sing-box )
* Custom Outbound
* Custom Config
* Custom Core

View File

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

View File

@@ -186,6 +186,8 @@ namespace NekoGui {
bean = new NekoGui_fmt::NaiveBean();
} else if (type == "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") {
bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_TUIC);
} else if (type == "custom") {

View File

@@ -199,13 +199,25 @@ namespace NekoGui_fmt {
if (!hopPort.trimmed().isEmpty()) outbound["hop_ports"] = hopPort;
if (authPayloadType == hysteria_auth_base64) outbound["auth"] = 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) {
outbound["type"] = "tuic";
outbound["uuid"] = uuid;
outbound["password"] = password;
outbound["congestion_control"] = congestionControl;
if (uos) {
outbound["udp_over_stream"]= true;
outbound["udp_over_stream"] = true;
} else {
outbound["udp_relay_mode"] = udpRelayMode;
}

View File

@@ -50,6 +50,16 @@ namespace NekoGui_fmt {
return 1;
};
auto hysteria2Core = [=] {
if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn || !hopPort.trimmed().isEmpty()) {
return 1;
}
return 2;
}
return 1;
};
auto tuicCore = [=] {
if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn) {
@@ -70,6 +80,8 @@ namespace NekoGui_fmt {
}
} else if (proxy_type == proxy_TUIC) {
return tuicCore();
} else if (proxy_type == proxy_Hysteria2) {
return hysteria2Core();
} else {
return hysteriaCore();
}
@@ -162,6 +174,78 @@ namespace NekoGui_fmt {
result.arguments = QStringList{"-c", TempFile};
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
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("hysteria")};

View File

@@ -7,6 +7,7 @@ namespace NekoGui_fmt {
public:
static constexpr int proxy_Hysteria = 0;
static constexpr int proxy_TUIC = 1;
static constexpr int proxy_Hysteria2 = 3;
int proxy_type = proxy_Hysteria;
// Hysteria
@@ -34,6 +35,9 @@ namespace NekoGui_fmt {
int hopInterval = 10;
QString hopPort = "";
// Hysteria 2 (Something same as hy1)
QString username = "";
// TUIC
QString uuid = "";
@@ -54,9 +58,7 @@ namespace NekoGui_fmt {
explicit QUICBean(int _proxy_type) : AbstractBean(0) {
proxy_type = _proxy_type;
if (proxy_type == proxy_Hysteria) {
_add(new configItem("protocol", &hyProtocol, itemType::integer));
_add(new configItem("authPayloadType", &authPayloadType, itemType::integer));
if (proxy_type == proxy_Hysteria || proxy_type == proxy_Hysteria2) {
_add(new configItem("authPayload", &authPayload, itemType::string));
_add(new configItem("obfsPassword", &obfsPassword, itemType::string));
_add(new configItem("uploadMbps", &uploadMbps, itemType::integer));
@@ -66,6 +68,13 @@ namespace NekoGui_fmt {
_add(new configItem("disableMtuDiscovery", &disableMtuDiscovery, itemType::boolean));
_add(new configItem("hopInterval", &hopInterval, itemType::integer));
_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) {
_add(new configItem("uuid", &uuid, 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);
if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", "");
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", "");
//
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("naive")
LOAD_TYPE("hysteria")
LOAD_TYPE("hysteria2")
LOAD_TYPE("tuic")
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");
@@ -177,7 +178,7 @@ void DialogEditProfile::typeSelected(const QString &newType) {
auto _innerWidget = new EditNaive(this);
innerWidget = _innerWidget;
innerEditor = _innerWidget;
} else if (type == "hysteria" || type == "tuic") {
} else if (type == "hysteria" || type == "hysteria2" || type == "tuic") {
auto _innerWidget = new EditQUIC(this);
innerWidget = _innerWidget;
innerEditor = _innerWidget;

View File

@@ -19,15 +19,13 @@ void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
this->ent = _ent;
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_INT(hopInterval);
P_LOAD_INT(uploadMbps);
P_LOAD_INT(downloadMbps);
P_LOAD_COMBO_INT(hyProtocol);
P_LOAD_BOOL(disableMtuDiscovery)
P_LOAD_STRING(obfsPassword);
P_LOAD_COMBO_INT(authPayloadType);
P_LOAD_STRING(authPayload);
P_LOAD_INT(streamReceiveWindow);
P_LOAD_INT(connectionReceiveWindow);
@@ -45,6 +43,21 @@ void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
ui->heartbeat->hide();
ui->heartbeat_l->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) {
P_LOAD_STRING(uuid);
P_LOAD_STRING(password);
@@ -104,6 +117,9 @@ bool EditQUIC::onEnd() {
P_SAVE_INT(streamReceiveWindow);
P_SAVE_INT(connectionReceiveWindow);
// Hysteria2
P_SAVE_STRING(username);
// TUIC
P_SAVE_STRING(uuid);
P_SAVE_STRING(password);

View File

@@ -166,23 +166,16 @@
</item>
<item>
<layout class="QGridLayout" name="obfuscation">
<item row="1" column="1">
<item row="2" column="1">
<widget class="MyLineEdit" name="obfsPassword"/>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="obfsPassword_l">
<property name="text">
<string>Obfs Password</string>
</property>
</widget>
</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">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
@@ -219,6 +212,23 @@
</item>
</layout>
</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>
</item>
<item>