From 26eefee4b9ae59e834c190d3e4513e36aa416cae Mon Sep 17 00:00:00 2001 From: Nova Date: Mon, 26 Aug 2024 17:22:02 +0330 Subject: [PATCH] fix: Restore header type for compatiblity with Xray --- fmt/Bean2CoreObj_box.cpp | 9 +++ fmt/Bean2Link.cpp | 11 ++++ fmt/Link2Bean.cpp | 13 ++++ fmt/V2RayStreamSettings.hpp | 2 + sub/GroupUpdater.cpp | 17 +++++ ui/edit/dialog_edit_profile.cpp | 26 +++++++- ui/edit/dialog_edit_profile.ui | 113 +++++++++++++++++++------------- 7 files changed, 143 insertions(+), 48 deletions(-) diff --git a/fmt/Bean2CoreObj_box.cpp b/fmt/Bean2CoreObj_box.cpp index d09c396..f6e4018 100644 --- a/fmt/Bean2CoreObj_box.cpp +++ b/fmt/Bean2CoreObj_box.cpp @@ -52,6 +52,15 @@ namespace NekoGui_fmt { transport["headers"] = QMapString2QJsonObject(headerMap); } outbound->insert("transport", transport); + } else if (header_type == "http") { + // TCP + headerType + QJsonObject transport{ + {"type", "http"}, + {"method", "GET"}, + {"path", path}, + {"headers", QJsonObject{{"Host", QListStr2QJsonArray(host.split(","))}}}, + }; + outbound->insert("transport", transport); } // 对应字段 tls diff --git a/fmt/Bean2Link.cpp b/fmt/Bean2Link.cpp index a37a36b..7681af3 100644 --- a/fmt/Bean2Link.cpp +++ b/fmt/Bean2Link.cpp @@ -60,6 +60,12 @@ namespace NekoGui_fmt { if (!stream->method.isEmpty()) query.addQueryItem("method", stream->method); } else if (stream->network == "grpc") { if (!stream->path.isEmpty()) query.addQueryItem("serviceName", stream->path); + } else if (stream->network == "tcp") { + if (stream->header_type == "http") { + if (!stream->path.isEmpty()) query.addQueryItem("path", stream->path); + query.addQueryItem("headerType", "http"); + query.addQueryItem("host", stream->host); + } } // mux @@ -156,6 +162,11 @@ namespace NekoGui_fmt { if (!stream->host.isEmpty()) query.addQueryItem("host", stream->host); } else if (stream->network == "grpc") { if (!stream->path.isEmpty()) query.addQueryItem("serviceName", stream->path); + } else if (stream->network == "tcp") { + if (stream->header_type == "http") { + query.addQueryItem("headerType", "http"); + query.addQueryItem("host", stream->host); + } } // mux diff --git a/fmt/Link2Bean.cpp b/fmt/Link2Bean.cpp index ebd64a2..d7b6f85 100644 --- a/fmt/Link2Bean.cpp +++ b/fmt/Link2Bean.cpp @@ -93,6 +93,12 @@ namespace NekoGui_fmt { stream->host = GetQueryValue(query, "host", ""); } else if (stream->network == "grpc") { stream->path = GetQueryValue(query, "serviceName", ""); + } else if (stream->network == "tcp") { + if (GetQueryValue(query, "headerType") == "http") { + stream->header_type = "http"; + stream->host = GetQueryValue(query, "host", ""); + stream->path = GetQueryValue(query, "path", ""); + } } // mux @@ -171,6 +177,7 @@ namespace NekoGui_fmt { stream->host = objN["host"].toString(); stream->path = objN["path"].toString(); stream->sni = objN["sni"].toString(); + stream->header_type = objN["type"].toString(); auto net = objN["net"].toString(); if (!net.isEmpty()) { if (net == "h2") { @@ -239,6 +246,12 @@ namespace NekoGui_fmt { stream->host = GetQueryValue(query, "host", ""); } else if (stream->network == "grpc") { stream->path = GetQueryValue(query, "serviceName", ""); + } else if (stream->network == "tcp") { + if (GetQueryValue(query, "headerType") == "http") { + stream->header_type = "http"; + stream->path = GetQueryValue(query, "path", ""); + stream->host = GetQueryValue(query, "host", ""); + } } return !(uuid.isEmpty() || serverAddress.isEmpty()); } diff --git a/fmt/V2RayStreamSettings.hpp b/fmt/V2RayStreamSettings.hpp index 5e582a6..3a8d80e 100644 --- a/fmt/V2RayStreamSettings.hpp +++ b/fmt/V2RayStreamSettings.hpp @@ -13,6 +13,7 @@ namespace NekoGui_fmt { QString host = ""; QString method = ""; QString headers = ""; + QString header_type = ""; QString sni = ""; QString alpn = ""; @@ -38,6 +39,7 @@ namespace NekoGui_fmt { _add(new configItem("cert", &certificate, itemType::string)); _add(new configItem("insecure", &allow_insecure, itemType::boolean)); _add(new configItem("headers", &headers, itemType::string)); + _add(new configItem("h_type", &header_type, itemType::string)); _add(new configItem("method", &method, itemType::string)); _add(new configItem("ed_name", &ws_early_data_name, itemType::string)); _add(new configItem("ed_len", &ws_early_data_length, itemType::integer)); diff --git a/sub/GroupUpdater.cpp b/sub/GroupUpdater.cpp index b86943b..93f7a16 100644 --- a/sub/GroupUpdater.cpp +++ b/sub/GroupUpdater.cpp @@ -459,6 +459,23 @@ namespace NekoGui_sub { } bean->stream->path = Node2QString(h2["path"]); } + auto tcp_http = NodeChild(proxy, {"http-opts", "http-opt"}); + if (tcp_http.IsMap()) { + bean->stream->network = "tcp"; + bean->stream->header_type = "http"; + auto headers = tcp_http["headers"]; + for (auto header: headers) { + if (Node2QString(header.first).toLower() == "host") { + bean->stream->host = Node2QString(header.second[0]); + } + break; + } + auto paths = tcp_http["path"]; + for (auto path: paths) { + bean->stream->path = Node2QString(path); + break; + } + } } else if (type == "hysteria") { auto bean = ent->QUICBean(); diff --git a/ui/edit/dialog_edit_profile.cpp b/ui/edit/dialog_edit_profile.cpp index a1a9186..9977884 100644 --- a/ui/edit/dialog_edit_profile.cpp +++ b/ui/edit/dialog_edit_profile.cpp @@ -32,7 +32,20 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId, network_title_base = ui->network_box->title(); connect(ui->network, &QComboBox::currentTextChanged, this, [=](const QString &txt) { ui->network_box->setTitle(network_title_base.arg(txt)); - if (txt == "grpc") { + if (txt == "tcp") { + ui->header_type->setVisible(true); + ui->header_type_l->setVisible(true); + ui->headers->setVisible(false); + ui->headers_l->setVisible(false); + ui->method->setVisible(false); + ui->method_l->setVisible(false); + ui->path->setVisible(true); + ui->path_l->setVisible(true); + ui->host->setVisible(true); + ui->host_l->setVisible(true); + } else if (txt == "grpc") { + ui->header_type->setVisible(false); + ui->header_type_l->setVisible(false); ui->headers->setVisible(false); ui->headers_l->setVisible(false); ui->method->setVisible(false); @@ -42,6 +55,8 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId, ui->host->setVisible(false); ui->host_l->setVisible(false); } else if (txt == "ws" || txt == "httpupgrade") { + ui->header_type->setVisible(false); + ui->header_type_l->setVisible(false); ui->headers->setVisible(true); ui->headers_l->setVisible(true); ui->method->setVisible(false); @@ -51,6 +66,8 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId, ui->host->setVisible(true); ui->host_l->setVisible(true); } else if (txt == "http") { + ui->header_type->setVisible(false); + ui->header_type_l->setVisible(false); ui->headers->setVisible(true); ui->headers_l->setVisible(true); ui->method->setVisible(true); @@ -60,6 +77,8 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId, ui->host->setVisible(true); ui->host_l->setVisible(true); } else { + ui->header_type->setVisible(false); + ui->header_type_l->setVisible(false); ui->headers->setVisible(false); ui->headers_l->setVisible(false); ui->method->setVisible(false); @@ -236,7 +255,6 @@ void DialogEditProfile::typeSelected(const QString &newType) { // 右边 stream auto stream = GetStreamSettings(ent->bean.get()); if (stream != nullptr) { - ui->network_box->setVisible(stream->network != "tcp"); ui->right_all_w->setVisible(true); ui->network->setCurrentText(stream->network); ui->security->setCurrentText(stream->security); @@ -252,6 +270,7 @@ void DialogEditProfile::typeSelected(const QString &newType) { ui->utlsFingerprint->setCurrentText(stream->utlsFingerprint); } ui->insecure->setChecked(stream->allow_insecure); + ui->header_type->setCurrentText(stream->header_type); ui->headers->setText(stream->headers); ui->ws_early_data_name->setText(stream->ws_early_data_name); ui->ws_early_data_length->setText(Int2String(stream->ws_early_data_length)); @@ -318,9 +337,11 @@ void DialogEditProfile::typeSelected(const QString &newType) { 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); @@ -382,6 +403,7 @@ bool DialogEditProfile::onEnd() { stream->utlsFingerprint = ui->utlsFingerprint->currentText(); stream->allow_insecure = ui->insecure->isChecked(); stream->headers = ui->headers->text(); + stream->header_type = ui->header_type->currentText(); stream->method = ui->method->text(); stream->ws_early_data_name = ui->ws_early_data_name->text(); stream->ws_early_data_length = ui->ws_early_data_length->text().toInt(); diff --git a/ui/edit/dialog_edit_profile.ui b/ui/edit/dialog_edit_profile.ui index 6a56ea3..45946a5 100644 --- a/ui/edit/dialog_edit_profile.ui +++ b/ui/edit/dialog_edit_profile.ui @@ -525,56 +525,14 @@ Network Settings (%1) - - - - - - - - - - - - - <html><head/><body><p>http host (ws/http/httpUpgrade)</p></body></html> - - - Host - - - - - - - - - - EarlyData Length - - - - - - - <html><head/><body><p>http path (ws/http/httpUpgrade)</p><p>serviceName (gRPC)</p></body></html> - - - Path - - - - + EarlyData Name - - - - + @@ -593,7 +551,39 @@ - + + + + EarlyData Length + + + + + + + + + + <html><head/><body><p>http path (ws/http/httpUpgrade)</p><p>serviceName (gRPC)</p></body></html> + + + Path + + + + + + + + + + + + + + + + <html><head/><body><p>Method of http request, will be converted to uppercase</p></body></html> @@ -603,8 +593,39 @@ + + + + <html><head/><body><p>http host (ws/http/httpUpgrade)</p></body></html> + + + Host + + + - + + + + + + + + + + + + http + + + + + + + + header type + +