From c41a61e2a9cf3618389188c6444fac32fd9e19d4 Mon Sep 17 00:00:00 2001 From: Nova Date: Sun, 10 Aug 2025 12:48:17 +0330 Subject: [PATCH] add tls fragment support --- include/configs/proxy/V2RayStreamSettings.hpp | 6 + include/ui/profile/dialog_edit_profile.ui | 186 +++++++++++---- include/ui/profile/edit_wireguard.ui | 220 +++++++++--------- src/configs/proxy/Bean2CoreObj_box.cpp | 20 +- src/configs/proxy/Bean2Link.cpp | 6 + src/configs/proxy/Json2Bean.cpp | 6 + src/configs/proxy/Link2Bean.cpp | 8 +- src/ui/profile/dialog_edit_profile.cpp | 13 ++ 8 files changed, 312 insertions(+), 153 deletions(-) diff --git a/include/configs/proxy/V2RayStreamSettings.hpp b/include/configs/proxy/V2RayStreamSettings.hpp index bdaf00e..a2ca109 100644 --- a/include/configs/proxy/V2RayStreamSettings.hpp +++ b/include/configs/proxy/V2RayStreamSettings.hpp @@ -20,6 +20,9 @@ namespace Configs { QString alpn = ""; QString certificate = ""; QString utlsFingerprint = ""; + bool enable_tls_fragment = false; + QString tls_fragment_fallback_delay; + bool enable_tls_record_fragment = false; bool allow_insecure = false; // ws early data QString ws_early_data_name = ""; @@ -44,6 +47,9 @@ namespace Configs { _add(new configItem("ed_name", &ws_early_data_name, itemType::string)); _add(new configItem("ed_len", &ws_early_data_length, itemType::integer)); _add(new configItem("utls", &utlsFingerprint, itemType::string)); + _add(new configItem("tls_frag", &enable_tls_fragment, itemType::boolean)); + _add(new configItem("tls_frag_fall_delay", &tls_fragment_fallback_delay, itemType::string)); + _add(new configItem("tls_record_frag", &enable_tls_record_fragment, itemType::boolean)); _add(new configItem("pbk", &reality_pbk, itemType::string)); _add(new configItem("sid", &reality_sid, itemType::string)); } diff --git a/include/ui/profile/dialog_edit_profile.ui b/include/ui/profile/dialog_edit_profile.ui index 9b3bd59..5531e24 100644 --- a/include/ui/profile/dialog_edit_profile.ui +++ b/include/ui/profile/dialog_edit_profile.ui @@ -16,6 +16,12 @@ 0 + + + 0 + 0 + + Edit @@ -285,7 +291,7 @@ - + 0 0 @@ -293,7 +299,7 @@ 400 - 613 + 500 @@ -632,52 +638,154 @@ + + + 0 + 0 + + TLS Camouflage Settings - - - - - - - - true - - - - - - - Reality public key. If not empty, turn TLS into REALITY. - - - Reality Pbk - - - - - - - Reality SID - - - - - + + + 0 + + + QLayout::SizeConstraint::SetMinimumSize + + + 7 + + + - + 0 0 - - Fingerprint - + + + 0 + + + QLayout::SizeConstraint::SetMinimumSize + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + <html><head/><body><p>May degrade performance, try record fragment first</p></body></html> + + + Enable TLS fragment + + + + + + + <html><head/><body><p>time format, like 500ms, 10ms etc</p></body></html> + + + Fallback Delay + + + + + + + + + + + + + Enable TLS Record Fragment + + + + - - + + + + + 7 + + + 7 + + + + + + 0 + 0 + + + + Fingerprint + + + + + + + true + + + + + + + Reality public key. If not empty, turn TLS into REALITY. + + + Reality Pbk + + + + + + + + + + Reality SID + + + + + + + + @@ -714,8 +822,6 @@ certificate_edit sni alpn - utlsFingerprint - reality_pbk diff --git a/include/ui/profile/edit_wireguard.ui b/include/ui/profile/edit_wireguard.ui index 1a34ab7..4267af0 100644 --- a/include/ui/profile/edit_wireguard.ui +++ b/include/ui/profile/edit_wireguard.ui @@ -6,115 +6,121 @@ 0 0 - 400 - 657 + 640 + 727 EditWireguard - - - - - Private Key - + + + + + + + + Private Key + + + + + + + + + + Public Key + + + + + + + + + + Pre Shared Key + + + + + + + + + + Reserved + + + + + + + + + + <html><head/><body><p>persistent_keepalive_interval in seconds</p></body></html> + + + <html><head/><body><p><br/></p></body></html> + + + Persistent Keepalive + + + + + + + + + + <html><head/><body><p>comma seperated list of subnets</p></body></html> + + + Local Address + + + + + + + + + + MTU + + + + + + + 1420 + + + + + + + Workers + + + + + + + + + + Use System Interface + + + + - - - - - - - Public Key - - - - - - - - - - Pre Shared Key - - - - - - - - - - Reserved - - - - - - - - - - <html><head/><body><p>persistent_keepalive_interval in seconds</p></body></html> - - - <html><head/><body><p><br/></p></body></html> - - - Persistent Keepalive - - - - - - - - - - <html><head/><body><p>comma seperated list of subnets</p></body></html> - - - Local Address - - - - - - - - - - MTU - - - - - - - 1420 - - - - - - - Workers - - - - - - - - - - Use System Interface - - - - + Amenzia Settings @@ -127,9 +133,6 @@ - - - @@ -137,8 +140,8 @@ - - + + @@ -147,6 +150,9 @@ + + + diff --git a/src/configs/proxy/Bean2CoreObj_box.cpp b/src/configs/proxy/Bean2CoreObj_box.cpp index ad3c92f..dc20243 100644 --- a/src/configs/proxy/Bean2CoreObj_box.cpp +++ b/src/configs/proxy/Bean2CoreObj_box.cpp @@ -12,8 +12,7 @@ namespace Configs { auto pathWithoutEd = SubStrBefore(path, "?ed="); if (!pathWithoutEd.isEmpty()) transport["path"] = pathWithoutEd; if (pathWithoutEd != path) { - auto ed = SubStrAfter(path, "?ed=").toInt(); - if (ed > 0) { + if (auto ed = SubStrAfter(path, "?ed=").toInt(); ed > 0) { transport["max_early_data"] = ed; transport["early_data_header_name"] = "Sec-WebSocket-Protocol"; } @@ -74,13 +73,18 @@ namespace Configs { if (!alpn.trimmed().isEmpty()) { tls["alpn"] = QListStr2QJsonArray(alpn.split(",")); } - QString fp = utlsFingerprint; - if (!fp.isEmpty()) { + if (QString fp = utlsFingerprint; !fp.isEmpty()) { tls["utls"] = QJsonObject{ {"enabled", true}, {"fingerprint", fp}, }; } + if (enable_tls_fragment) + { + tls["fragment"] = enable_tls_fragment; + if (!tls_fragment_fallback_delay.isEmpty()) tls["fragment_fallback_delay"] = tls_fragment_fallback_delay; + } + if (enable_tls_record_fragment) tls["record_fragment"] = enable_tls_record_fragment; outbound->insert("tls", tls); } else if (security == "reality") { QJsonObject tls{{"enabled", true}}; @@ -105,6 +109,12 @@ namespace Configs { {"fingerprint", fp}, }; } + if (enable_tls_fragment) + { + tls["fragment"] = enable_tls_fragment; + if (!tls_fragment_fallback_delay.isEmpty()) tls["fragment_fallback_delay"] = tls_fragment_fallback_delay; + } + if (enable_tls_record_fragment) tls["record_fragment"] = enable_tls_record_fragment; outbound->insert("tls", tls); } @@ -277,7 +287,7 @@ namespace Configs { auto tun_name = "throne-wg"; #ifdef Q_OS_MACOS - tun_name = "uwg9"; + tun_name = ""; #endif QJsonObject peer{ diff --git a/src/configs/proxy/Bean2Link.cpp b/src/configs/proxy/Bean2Link.cpp index a9dcfcf..4d8b2b7 100644 --- a/src/configs/proxy/Bean2Link.cpp +++ b/src/configs/proxy/Bean2Link.cpp @@ -39,6 +39,9 @@ namespace Configs { if (!stream->alpn.isEmpty()) query.addQueryItem("alpn", stream->alpn); if (stream->allow_insecure) query.addQueryItem("allowInsecure", "1"); if (!stream->utlsFingerprint.isEmpty()) query.addQueryItem("fp", stream->utlsFingerprint); + if (stream->enable_tls_fragment) query.addQueryItem("fragment", "1"); + if (!stream->tls_fragment_fallback_delay.isEmpty()) query.addQueryItem("fragment_fallback_delay", stream->tls_fragment_fallback_delay); + if (stream->enable_tls_record_fragment) query.addQueryItem("record_fragment", "1"); if (stream->security == "reality") { query.addQueryItem("pbk", stream->reality_pbk); @@ -145,6 +148,9 @@ namespace Configs { } else { query.addQueryItem("fp", stream->utlsFingerprint); } + if (stream->enable_tls_fragment) query.addQueryItem("fragment", "1"); + if (!stream->tls_fragment_fallback_delay.isEmpty()) query.addQueryItem("fragment_fallback_delay", stream->tls_fragment_fallback_delay); + if (stream->enable_tls_record_fragment) query.addQueryItem("record_fragment", "1"); if (stream->security == "reality") { query.addQueryItem("pbk", stream->reality_pbk); diff --git a/src/configs/proxy/Json2Bean.cpp b/src/configs/proxy/Json2Bean.cpp index 6f0ba33..615445c 100644 --- a/src/configs/proxy/Json2Bean.cpp +++ b/src/configs/proxy/Json2Bean.cpp @@ -141,6 +141,9 @@ namespace Configs stream->reality_pbk = obj["tls"].toObject()["reality"].toObject()["public_key"].toString(); stream->reality_sid = obj["tls"].toObject()["reality"].toObject()["short_id"].toString(); stream->utlsFingerprint = obj["tls"].toObject()["utls"].toObject()["fingerprint"].toString(); + stream->enable_tls_fragment = obj["tls"].toObject()["fragment"].toBool(); + stream->tls_fragment_fallback_delay = obj["tls"].toObject()["fragment_fallback_delay"].toString(); + stream->enable_tls_record_fragment = obj["tls"].toObject()["record_fragment"].toBool(); stream->sni = obj["tls"].toObject()["server_name"].toString(); stream->alpn = obj["tls"].toObject()["alpn"].isArray() ? QJsonArray2QListString(obj["tls"].toObject()["alpn"].toArray()).join(",") : obj["tls"].toObject()["alpn"].toString(); stream->allow_insecure = obj["tls"].toObject()["insecure"].toBool(); @@ -183,6 +186,9 @@ namespace Configs stream->reality_pbk = obj["tls"].toObject()["reality"].toObject()["public_key"].toString(); stream->reality_sid = obj["tls"].toObject()["reality"].toObject()["short_id"].toString(); stream->utlsFingerprint = obj["tls"].toObject()["utls"].toObject()["fingerprint"].toString(); + stream->enable_tls_fragment = obj["tls"].toObject()["fragment"].toBool(); + stream->tls_fragment_fallback_delay = obj["tls"].toObject()["fragment_fallback_delay"].toString(); + stream->enable_tls_record_fragment = obj["tls"].toObject()["record_fragment"].toBool(); stream->sni = obj["tls"].toObject()["server_name"].toString(); stream->alpn = obj["tls"].toObject()["alpn"].isArray() ? QJsonArray2QListString(obj["tls"].toObject()["alpn"].toArray()).join(",") : obj["tls"].toObject()["alpn"].toString(); stream->allow_insecure = obj["tls"].toObject()["insecure"].toBool(); diff --git a/src/configs/proxy/Link2Bean.cpp b/src/configs/proxy/Link2Bean.cpp index 5d30830..9c5abdc 100644 --- a/src/configs/proxy/Link2Bean.cpp +++ b/src/configs/proxy/Link2Bean.cpp @@ -71,8 +71,11 @@ namespace Configs { stream->reality_pbk = GetQueryValue(query, "pbk", ""); stream->reality_sid = GetQueryValue(query, "sid", ""); stream->utlsFingerprint = GetQueryValue(query, "fp", ""); + if (query.queryItemValue("fragment") == "1") stream->enable_tls_fragment = true; + stream->tls_fragment_fallback_delay = query.queryItemValue("fragment_fallback_delay"); + if (query.queryItemValue("record_fragment") == "1") stream->enable_tls_record_fragment = true; if (stream->utlsFingerprint.isEmpty()) { - stream->utlsFingerprint = Configs::dataStore->utlsFingerprint; + stream->utlsFingerprint = dataStore->utlsFingerprint; } if (stream->security.isEmpty()) { if (!sni1.isEmpty() || !sni2.isEmpty()) stream->security = "tls"; @@ -224,6 +227,9 @@ namespace Configs { if (stream->utlsFingerprint.isEmpty()) { stream->utlsFingerprint = Configs::dataStore->utlsFingerprint; } + if (query.queryItemValue("fragment") == "1") stream->enable_tls_fragment = true; + stream->tls_fragment_fallback_delay = query.queryItemValue("fragment_fallback_delay"); + if (query.queryItemValue("record_fragment") == "1") stream->enable_tls_record_fragment = true; // mux auto mux_str = GetQueryValue(query, "mux", ""); diff --git a/src/ui/profile/dialog_edit_profile.cpp b/src/ui/profile/dialog_edit_profile.cpp index f47a33b..69eab06 100644 --- a/src/ui/profile/dialog_edit_profile.cpp +++ b/src/ui/profile/dialog_edit_profile.cpp @@ -134,6 +134,12 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId, }); emit ui->security->currentTextChanged(ui->security->currentText()); + // for fragment + connect(ui->tls_frag, &QCheckBox::checkStateChanged, this, [=](bool state) + { + ui->tls_frag_fall_delay->setEnabled(state); + }); + // mux setting changed connect(ui->multiplex, &QComboBox::currentTextChanged, this, [=](const QString &txt) { if (txt == "Off") { @@ -287,6 +293,10 @@ void DialogEditProfile::typeSelected(const QString &newType) { } else { ui->utlsFingerprint->setCurrentText(stream->utlsFingerprint); } + ui->tls_frag->setChecked(stream->enable_tls_fragment); + ui->tls_frag_fall_delay->setEnabled(stream->enable_tls_fragment); + ui->tls_frag_fall_delay->setText(stream->tls_fragment_fallback_delay); + ui->tls_rec_frag->setChecked(stream->enable_tls_record_fragment); ui->insecure->setChecked(stream->allow_insecure); ui->header_type->setCurrentText(stream->header_type); ui->headers->setText(stream->headers); @@ -423,6 +433,9 @@ bool DialogEditProfile::onEnd() { stream->sni = ui->sni->text(); stream->alpn = ui->alpn->text(); stream->utlsFingerprint = ui->utlsFingerprint->currentText(); + stream->enable_tls_fragment = ui->tls_frag->isChecked(); + stream->tls_fragment_fallback_delay = ui->tls_frag_fall_delay->text(); + stream->enable_tls_record_fragment = ui->tls_rec_frag->isChecked(); stream->allow_insecure = ui->insecure->isChecked(); stream->headers = ui->headers->text(); stream->header_type = ui->header_type->currentText();