Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added fragment to the preferences settings #2839

Merged
merged 12 commits into from Feb 14, 2024
4 changes: 4 additions & 0 deletions V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt
Expand Up @@ -44,6 +44,10 @@ object AppConfig {
const val PREF_MUX_CONCURRENCY = "pref_mux_concurency"
const val PREF_MUX_XUDP_CONCURRENCY = "pref_mux_xudp_concurency"
const val PREF_MUX_XUDP_QUIC = "pref_mux_xudp_quic"
const val PREF_FRAGMENT_ENABLED = "pref_fragment_enabled"
const val PREF_FRAGMENT_PACKETS = "pref_fragment_packets"
const val PREF_FRAGMENT_LENGTH = "pref_fragment_length"
const val PREF_FRAGMENT_INTERVAL = "pref_fragment_interval"

const val HTTP_PROTOCOL: String = "http://"
const val HTTPS_PROTOCOL: String = "https://"
Expand Down
4 changes: 4 additions & 0 deletions V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ServerConfig.kt
Expand Up @@ -56,6 +56,10 @@ data class ServerConfig(
return fullConfig?.getProxyOutbound()
}

fun getFragmentOutbound(): V2rayConfig.OutboundBean? {
return fullConfig?.getFragmentOutbound()
}

fun getAllOutboundTags(): MutableList<String> {
if (configType != EConfigType.CUSTOM) {
return mutableListOf(TAG_AGENT, TAG_DIRECT, TAG_BLOCKED)
Expand Down
15 changes: 12 additions & 3 deletions V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt
Expand Up @@ -61,13 +61,13 @@ data class V2rayConfig(
val metadataOnly: Boolean? = null)
}

data class OutboundBean(val tag: String = "proxy",
data class OutboundBean(var tag: String = "proxy",
var protocol: String,
var settings: OutSettingsBean? = null,
var streamSettings: StreamSettingsBean? = null,
val proxySettings: Any? = null,
val sendThrough: String? = null,
val mux: MuxBean? = MuxBean(false)) {
var mux: MuxBean? = MuxBean(false)) {

data class OutSettingsBean(var vnext: List<VnextBean>? = null,
var fragment: FragmentBean? = null,
Expand Down Expand Up @@ -141,7 +141,7 @@ data class V2rayConfig(
var realitySettings: TlsSettingsBean? = null,
var grpcSettings: GrpcSettingsBean? = null,
val dsSettings: Any? = null,
val sockopt: SockoptBean? = null
var sockopt: SockoptBean? = null
) {

data class TcpSettingsBean(var header: HeaderBean = HeaderBean(),
Expand Down Expand Up @@ -475,6 +475,15 @@ data class V2rayConfig(
return null
}

fun getFragmentOutbound(): OutboundBean? {
outbounds.forEach { outbound ->
if (outbound.protocol == "freedom" && outbound.tag == "fragment") {
return outbound
}
}
return null
}

fun toPrettyPrinting(): String {
return GsonBuilder()
.setPrettyPrinting()
Expand Down
52 changes: 49 additions & 3 deletions V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt
Expand Up @@ -41,6 +41,10 @@ class SettingsActivity : BaseActivity() {
private val muxXudpConcurrency by lazy { findPreference<EditTextPreference>(AppConfig.PREF_MUX_XUDP_CONCURRENCY) }
private val muxXudpQuic by lazy { findPreference<ListPreference>(AppConfig.PREF_MUX_XUDP_QUIC) }

private val fragment by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_FRAGMENT_ENABLED) }
private val fragmentPackets by lazy { findPreference<ListPreference>(AppConfig.PREF_FRAGMENT_PACKETS) }
private val fragmentLength by lazy { findPreference<EditTextPreference>(AppConfig.PREF_FRAGMENT_LENGTH) }
private val fragmentInterval by lazy { findPreference<EditTextPreference>(AppConfig.PREF_FRAGMENT_INTERVAL) }

// val autoRestart by lazy { findPreference(PREF_AUTO_RESTART) as CheckBoxPreference }
private val remoteDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_REMOTE_DNS) }
Expand Down Expand Up @@ -168,6 +172,23 @@ class SettingsActivity : BaseActivity() {
updateMuxXudpConcurrency(newValue as String)
true
}

fragment?.setOnPreferenceChangeListener { _, newValue ->
updateFragment(newValue as Boolean)
true
}
fragmentPackets?.setOnPreferenceChangeListener { _, newValue ->
updateFragmentPackets(newValue as String)
true
}
fragmentLength?.setOnPreferenceChangeListener { _, newValue ->
updateFragmentLength(newValue as String)
true
}
fragmentInterval?.setOnPreferenceChangeListener { _, newValue ->
updateFragmentInterval(newValue as String)
true
}
}

override fun onStart() {
Expand All @@ -184,6 +205,10 @@ class SettingsActivity : BaseActivity() {
updateMux(defaultSharedPreferences.getBoolean(AppConfig.PREF_MUX_ENABLED, false))
muxConcurrency?.summary = defaultSharedPreferences.getString(AppConfig.PREF_MUX_CONCURRENCY, "8")
muxXudpConcurrency?.summary = defaultSharedPreferences.getString(AppConfig.PREF_MUX_XUDP_CONCURRENCY, "8")
updateFragment(defaultSharedPreferences.getBoolean(AppConfig.PREF_FRAGMENT_ENABLED, false))
fragmentPackets?.summary = defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_PACKETS, "tlshello")
fragmentLength?.summary = defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_LENGTH, "50-100")
fragmentInterval?.summary = defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20")
autoUpdateInterval?.summary = defaultSharedPreferences.getString(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL)
autoUpdateInterval?.isEnabled = defaultSharedPreferences.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false)

Expand Down Expand Up @@ -261,9 +286,9 @@ class SettingsActivity : BaseActivity() {

private fun updateMux(enabled: Boolean) {
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity())
muxConcurrency?.isEnabled = enabled
muxXudpConcurrency?.isEnabled = enabled
muxXudpQuic?.isEnabled = enabled
muxConcurrency?.isVisible = enabled
muxXudpConcurrency?.isVisible = enabled
muxXudpQuic?.isVisible = enabled
if (enabled) {
updateMuxConcurrency(defaultSharedPreferences.getString(AppConfig.PREF_MUX_CONCURRENCY, "8"))
updateMuxXudpConcurrency(defaultSharedPreferences.getString(AppConfig.PREF_MUX_XUDP_CONCURRENCY, "8"))
Expand All @@ -287,6 +312,27 @@ class SettingsActivity : BaseActivity() {
muxXudpQuic?.isEnabled = concurrency >= 0
}
}

private fun updateFragment(enabled: Boolean) {
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity())
fragmentPackets?.isVisible = enabled
fragmentLength?.isVisible = enabled
fragmentInterval?.isVisible = enabled
if (enabled) {
updateFragmentPackets(defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_PACKETS, "tlshello"))
updateFragmentLength(defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_LENGTH, "50-100"))
updateFragmentInterval(defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20"))
}
}
private fun updateFragmentPackets(value: String?) {
fragmentPackets?.summary = value.toString()
}
private fun updateFragmentLength(value: String?) {
fragmentLength?.summary = value.toString()
}
private fun updateFragmentInterval(value: String?) {
fragmentInterval?.summary = value.toString()
}
}

fun onModeHelpClicked(view: View) {
Expand Down
32 changes: 27 additions & 5 deletions V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt
Expand Up @@ -38,7 +38,8 @@ object V2rayConfigUtil {
return Result(true, customConfig)
}
val outbound = config.getProxyOutbound() ?: return Result(false, "")
val result = getV2rayNonCustomConfig(context, outbound)
val fragmentOutbound = config.getFragmentOutbound() ?: V2rayConfig.OutboundBean(protocol = "freedom")
val result = getV2rayNonCustomConfig(context, outbound, fragmentOutbound)
//Log.d(ANG_PACKAGE, result.content)
return result
} catch (e: Exception) {
Expand All @@ -50,7 +51,7 @@ object V2rayConfigUtil {
/**
* 生成v2ray的客户端配置文件
*/
private fun getV2rayNonCustomConfig(context: Context, outbound: V2rayConfig.OutboundBean): Result {
private fun getV2rayNonCustomConfig(context: Context, outbound: V2rayConfig.OutboundBean, fragmentOutbound: V2rayConfig.OutboundBean): Result {
val result = Result(false, "")
//取得默认配置
val assets = Utils.readTextFromAssets(context, "v2ray_config.json")
Expand All @@ -66,9 +67,12 @@ object V2rayConfigUtil {

inbounds(v2rayConfig)

updateOutboundWithGlobalSettings(outbound)
updateOutboundWithGlobalSettings(outbound, fragmentOutbound)

v2rayConfig.outbounds[0] = outbound
if (fragmentOutbound.tag == "fragment") {
v2rayConfig.outbounds[1] = fragmentOutbound
}

routing(v2rayConfig)

Expand Down Expand Up @@ -401,7 +405,7 @@ object V2rayConfigUtil {
return true
}

private fun updateOutboundWithGlobalSettings(outbound: V2rayConfig.OutboundBean): Boolean {
private fun updateOutboundWithGlobalSettings(outbound: V2rayConfig.OutboundBean, fragmentOutbound: V2rayConfig.OutboundBean): Boolean {
try {
var muxEnabled = settingsStorage?.decodeBool(AppConfig.PREF_MUX_ENABLED, false)
val protocol = outbound.protocol
Expand Down Expand Up @@ -463,11 +467,29 @@ object V2rayConfigUtil {
outbound.streamSettings?.tcpSettings?.header?.request?.headers?.Host = host!!
}

if(settingsStorage?.decodeBool(AppConfig.PREF_FRAGMENT_ENABLED, false) == true) {
fragmentOutbound.tag = "fragment"
fragmentOutbound.mux = null
fragmentOutbound.settings = V2rayConfig.OutboundBean.OutSettingsBean(
fragment = V2rayConfig.OutboundBean.OutSettingsBean.FragmentBean(
packets = settingsStorage?.decodeString(AppConfig.PREF_FRAGMENT_PACKETS) ?: "tlshello",
length = settingsStorage?.decodeString(AppConfig.PREF_FRAGMENT_LENGTH) ?: "50-100",
interval = settingsStorage?.decodeString(AppConfig.PREF_FRAGMENT_INTERVAL) ?: "10-20"))
fragmentOutbound.streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean(
sockopt = V2rayConfig.OutboundBean.StreamSettingsBean.SockoptBean(
TcpNoDelay = true,
mark = 255))
}
if (fragmentOutbound.tag == "fragment") {
val sockopt = outbound.streamSettings?.sockopt ?: V2rayConfig.OutboundBean.StreamSettingsBean.SockoptBean()
sockopt.dialerProxy = "fragment"
sockopt.mark = 255
outbound.streamSettings?.sockopt = sockopt
}
} catch (e: Exception) {
e.printStackTrace()
return false
}
return true
}

}
Expand Up @@ -41,6 +41,9 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
AppConfig.PREF_V2RAY_ROUTING_BLOCKED,
AppConfig.PREF_V2RAY_ROUTING_DIRECT,
AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,
AppConfig.PREF_FRAGMENT_PACKETS,
AppConfig.PREF_FRAGMENT_LENGTH,
AppConfig.PREF_FRAGMENT_INTERVAL,
AppConfig.PREF_MUX_XUDP_QUIC, -> {
settingsStorage?.encode(key, sharedPreferences.getString(key, ""))
}
Expand All @@ -55,6 +58,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
AppConfig.PREF_CONFIRM_REMOVE,
AppConfig.PREF_START_SCAN_IMMEDIATE,
AppConfig.SUBSCRIPTION_AUTO_UPDATE,
AppConfig.PREF_FRAGMENT_ENABLED,
AppConfig.PREF_MUX_ENABLED, -> {
settingsStorage?.encode(key, sharedPreferences.getBoolean(key, false))
}
Expand Down
4 changes: 4 additions & 0 deletions V2rayNG/app/src/main/res/values/arrays.xml
Expand Up @@ -60,6 +60,10 @@
<item>reality</item>
</string-array>

<string-array name="fragment_packets" translatable="false">
<item>tlshello</item>
</string-array>

<string-array name="streamsecurity_utls" translatable="false">
<item></item>
<item>chrome</item>
Expand Down
4 changes: 4 additions & 0 deletions V2rayNG/app/src/main/res/values/strings.xml
Expand Up @@ -240,6 +240,10 @@

<string name="import_subscription_success">Subscription imported Successfully</string>
<string name="import_subscription_failure">Import subscription failed</string>
<string name="title_pref_fragment_packets">Fragment Packets</string>
<string name="title_pref_fragment_length">Fragment Length (min-max)</string>
<string name="title_pref_fragment_interval">Fragment Interval (min-max)</string>
<string name="title_pref_fragment_enabled">Enable Fragment</string>

<string-array name="share_method">
<item>QRcode</item>
Expand Down
22 changes: 22 additions & 0 deletions V2rayNG/app/src/main/res/xml/pref_settings.xml
Expand Up @@ -32,6 +32,28 @@
android:summary="%s"
android:title="@string/title_pref_mux_xudp_quic" />

<CheckBoxPreference
android:key="pref_fragment_enabled"
android:title="@string/title_pref_fragment_enabled"/>

<ListPreference
android:key="pref_fragment_packets"
android:defaultValue="tlshello"
android:entries="@array/fragment_packets"
android:entryValues="@array/fragment_packets"
android:summary="%s"
android:title="@string/title_pref_fragment_packets" />

<EditTextPreference
android:key="pref_fragment_length"
android:summary="50-100"
android:title="@string/title_pref_fragment_length" />

<EditTextPreference
android:key="pref_fragment_interval"
android:summary="10-20"
android:title="@string/title_pref_fragment_interval" />

<PreferenceCategory android:title="@string/title_vpn_settings">
<CheckBoxPreference
android:key="pref_per_app_proxy"
Expand Down