Support new fragment (#5437)

* Support new fragment

* Fix
This commit is contained in:
DHR60 authored and GitHub committed 2026-04-02 09:30:31 +08:00
1 parent b61cad5a5f
commit 9dc1b1f2cf
2 files changed
+69 -53

No files matched your search

@@ -68,8 +68,6 @@ data class V2rayConfig(
) {
data class OutSettingsBean(
var vnext: List<VnextBean>? = null,
var fragment: FragmentBean? = null,
var noises: List<NoiseBean>? = null,
var servers: List<ServersBean>? = null,
/*Blackhole*/
var response: Response? = null,
@@ -108,18 +106,6 @@ data class V2rayConfig(
)
}
data class FragmentBean(
var packets: String? = null,
var length: String? = null,
var interval: String? = null
)
data class NoiseBean(
var type: String? = null,
var packet: String? = null,
var delay: String? = null
)
data class ServersBean(
var address: String = "",
var method: String? = null,
@@ -306,9 +292,25 @@ data class V2rayConfig(
var settings: MaskSettingsBean? = null
) {
data class MaskSettingsBean(
var password: String? = null,
var domain: String? = null
)
val password: String? = null,
val domain: String? = null,
// fragment
val packets: String? = null,
val length: String? = null,
val delay: String? = null,
// val maxSplit: String? = null,
// noise
val reset: Int? = null,
val noise: List<NoiseMaskBean>? = null
) {
data class NoiseMaskBean(
val rand: String? = null,
// val randRange: String? = null,
// val type: String? = null,
// val packet: String? = null,
val delay: String? = null,
)
}
}
data class QuicParamsBean(
var congestion: String? = null,
@@ -710,8 +710,6 @@ object V2rayConfigManager {
} else {
v2rayConfig.outbounds.add(outbound)
}
updateOutboundFragment(v2rayConfig)
return true
}
@@ -955,68 +953,80 @@ object V2rayConfigManager {
*
* Configures packet fragmentation for TLS and REALITY protocols if enabled.
*
* @param v2rayConfig The V2ray configuration object to be modified
* @param streamSettings The streamSettings object to be modified
* @return true if fragment configuration was successful, false otherwise
*/
private fun updateOutboundFragment(v2rayConfig: V2rayConfig): Boolean {
private fun updateOutboundFragment(streamSettings: StreamSettingsBean): Boolean {
try {
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_FRAGMENT_ENABLED, false) == false) {
return true
}
if (v2rayConfig.outbounds[0].streamSettings?.security != AppConfig.TLS
&& v2rayConfig.outbounds[0].streamSettings?.security != AppConfig.REALITY
if (streamSettings.security != AppConfig.TLS
&& streamSettings.security != AppConfig.REALITY
) {
return true
}
val fragmentOutbound =
OutboundBean(
protocol = AppConfig.PROTOCOL_FREEDOM,
tag = AppConfig.TAG_FRAGMENT,
mux = null
)
if (streamSettings.sockopt?.dialerProxy.isNotNullEmpty()) {
return true
}
var packets =
MmkvManager.decodeSettingsString(AppConfig.PREF_FRAGMENT_PACKETS) ?: "tlshello"
if (v2rayConfig.outbounds[0].streamSettings?.security == AppConfig.REALITY
if (streamSettings.security == AppConfig.REALITY
&& packets == "tlshello"
) {
packets = "1-3"
} else if (v2rayConfig.outbounds[0].streamSettings?.security == AppConfig.TLS
} else if (streamSettings.security == AppConfig.TLS
&& packets != "tlshello"
) {
packets = "tlshello"
}
fragmentOutbound.settings = OutSettingsBean(
fragment = OutSettingsBean.FragmentBean(
val fragmentMask = StreamSettingsBean.FinalMaskBean.MaskBean(
type = "fragment",
settings = StreamSettingsBean.FinalMaskBean.MaskBean.MaskSettingsBean(
packets = packets,
length = MmkvManager.decodeSettingsString(AppConfig.PREF_FRAGMENT_LENGTH)
?: "50-100",
interval = MmkvManager.decodeSettingsString(AppConfig.PREF_FRAGMENT_INTERVAL)
delay = MmkvManager.decodeSettingsString(AppConfig.PREF_FRAGMENT_INTERVAL)
?: "10-20"
),
noises = listOf(
OutSettingsBean.NoiseBean(
type = "rand",
packet = "10-20",
delay = "10-16",
)
)
val noiseMask = StreamSettingsBean.FinalMaskBean.MaskBean(
type = "noise",
settings = StreamSettingsBean.FinalMaskBean.MaskBean.MaskSettingsBean(
noise = listOf(
StreamSettingsBean.FinalMaskBean.MaskBean.MaskSettingsBean.NoiseMaskBean(
rand = "10-20",
delay = "10-16",
)
)
),
)
fragmentOutbound.streamSettings = StreamSettingsBean(
sockopt = StreamSettingsBean.SockoptBean(
TcpNoDelay = true,
mark = 255
)
)
v2rayConfig.outbounds.add(fragmentOutbound)
//proxy chain
v2rayConfig.outbounds[0].streamSettings?.sockopt =
StreamSettingsBean.SockoptBean(
dialerProxy = AppConfig.TAG_FRAGMENT
)
val finalMaskObj = streamSettings.finalmask?.let { existingFinalMask ->
JsonUtil.parseString(JsonUtil.toJson(existingFinalMask))
} ?: com.google.gson.JsonObject()
// finalmask.tcp / finalmask.udp are arrays; prepend mask at index 0.
fun prependMask(scope: String, mask: StreamSettingsBean.FinalMaskBean.MaskBean) {
val current = finalMaskObj.get(scope)
if (current != null && current.isJsonArray && current.asJsonArray.size() > 0) {
return
}
val newArray = JsonArray()
newArray.add(JsonUtil.parseString(JsonUtil.toJson(mask)))
if (current != null && current.isJsonArray) {
current.asJsonArray.forEach { newArray.add(it) }
}
finalMaskObj.add(scope, newArray)
}
prependMask("tcp", fragmentMask)
prependMask("udp", noiseMask)
streamSettings.finalmask = finalMaskObj
} catch (e: Exception) {
Log.e(AppConfig.TAG, "Failed to update outbound fragment", e)
return false
@@ -1402,6 +1412,10 @@ object V2rayConfigManager {
streamSettings.tlsSettings = null
streamSettings.realitySettings = tlsSetting
}
if (profileItem.finalMask.isNullOrEmpty()) {
updateOutboundFragment(streamSettings)
}
}
//endregion