Improvements and fixes (v 1.1.1):

- Added TCP Fast Open and UDP fake count to UI editor
- Added IPv6 support
- Changed default split position to 2
- Improved DNS domain validation
- Adjusted QuickTile icon
- Added russian description for fastlane
This commit is contained in:
dovecoteescapee 2024-08-22 01:43:18 +03:00
parent 7a3850c7d3
commit 834b2bc1d2
24 changed files with 114 additions and 37 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

View File

@ -11,8 +11,8 @@ android {
applicationId = "io.github.dovecoteescapee.byedpi" applicationId = "io.github.dovecoteescapee.byedpi"
minSdk = 21 minSdk = 21
targetSdk = 34 targetSdk = 34
versionCode = 8 versionCode = 9
versionName = "1.1.0" versionName = "1.1.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

View File

@ -89,7 +89,9 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
jint tls_record_split_position, jint tls_record_split_position,
jboolean tls_record_split_at_sni, jboolean tls_record_split_at_sni,
jint hosts_mode, jint hosts_mode,
jstring hosts) { jstring hosts,
jboolean tfo,
jint udp_fake_count) {
struct sockaddr_ina s; struct sockaddr_ina s;
const char *address = (*env)->GetStringUTFChars(env, ip, 0); const char *address = (*env)->GetStringUTFChars(env, ip, 0);
@ -105,6 +107,7 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
params.max_open = max_connections; params.max_open = max_connections;
params.bfsize = buffer_size; params.bfsize = buffer_size;
params.resolve = !no_domain; params.resolve = !no_domain;
params.tfo = tfo;
if (custom_ttl) { if (custom_ttl) {
params.def_ttl = default_ttl; params.def_ttl = default_ttl;
@ -166,6 +169,7 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
} }
dp->ttl = fake_ttl; dp->ttl = fake_ttl;
dp->udp_fake_count = udp_fake_count;
dp->proto = dp->proto =
IS_HTTP * desync_http | IS_HTTP * desync_http |
IS_HTTPS * desync_https | IS_HTTPS * desync_https |

View File

@ -77,7 +77,9 @@ class ByeDpiProxy {
tlsRecordSplitPosition = preferences.tlsRecordSplitPosition, tlsRecordSplitPosition = preferences.tlsRecordSplitPosition,
tlsRecordSplitAtSni = preferences.tlsRecordSplitAtSni, tlsRecordSplitAtSni = preferences.tlsRecordSplitAtSni,
hostsMode = preferences.hostsMode.ordinal, hostsMode = preferences.hostsMode.ordinal,
hosts = preferences.hosts hosts = preferences.hosts,
tcpFastOpen = preferences.tcpFastOpen,
udpFakeCount = preferences.udpFakeCount,
) )
} }
@ -107,7 +109,9 @@ class ByeDpiProxy {
tlsRecordSplitPosition: Int, tlsRecordSplitPosition: Int,
tlsRecordSplitAtSni: Boolean, tlsRecordSplitAtSni: Boolean,
hostsMode: Int, hostsMode: Int,
hosts: String? hosts: String?,
tcpFastOpen: Boolean,
udpFakeCount: Int,
): Int ): Int
private external fun jniStartProxy(fd: Int): Int private external fun jniStartProxy(fd: Int): Int

View File

@ -57,6 +57,8 @@ class ByeDpiProxyUIPreferences(
tlsRecordSplitAtSni: Boolean? = null, tlsRecordSplitAtSni: Boolean? = null,
hostsMode: HostsMode? = null, hostsMode: HostsMode? = null,
hosts: String? = null, hosts: String? = null,
tcpFastOpen: Boolean? = null,
udpFakeCount: Int? = null,
) : ByeDpiProxyPreferences { ) : ByeDpiProxyPreferences {
val ip: String = ip ?: "127.0.0.1" val ip: String = ip ?: "127.0.0.1"
val port: Int = port ?: 1080 val port: Int = port ?: 1080
@ -69,7 +71,7 @@ class ByeDpiProxyUIPreferences(
val desyncHttps: Boolean = desyncHttps ?: true val desyncHttps: Boolean = desyncHttps ?: true
val desyncUdp: Boolean = desyncUdp ?: false val desyncUdp: Boolean = desyncUdp ?: false
val desyncMethod: DesyncMethod = desyncMethod ?: DesyncMethod.Disorder val desyncMethod: DesyncMethod = desyncMethod ?: DesyncMethod.Disorder
val splitPosition: Int = splitPosition ?: 3 val splitPosition: Int = splitPosition ?: 2
val splitAtHost: Boolean = splitAtHost ?: false val splitAtHost: Boolean = splitAtHost ?: false
val fakeTtl: Int = fakeTtl ?: 8 val fakeTtl: Int = fakeTtl ?: 8
val fakeSni: String = fakeSni ?: "www.iana.org" val fakeSni: String = fakeSni ?: "www.iana.org"
@ -86,6 +88,8 @@ class ByeDpiProxyUIPreferences(
val hosts: String? = val hosts: String? =
if (this.hostsMode == HostsMode.Disable) null if (this.hostsMode == HostsMode.Disable) null
else hosts?.trim() else hosts?.trim()
val tcpFastOpen: Boolean = tcpFastOpen ?: false
val udpFakeCount: Int = udpFakeCount ?: 0
constructor(preferences: SharedPreferences) : this( constructor(preferences: SharedPreferences) : this(
ip = preferences.getString("byedpi_proxy_ip", null), ip = preferences.getString("byedpi_proxy_ip", null),
@ -119,7 +123,9 @@ class ByeDpiProxyUIPreferences(
HostsMode.Whitelist -> preferences.getString("byedpi_hosts_whitelist", null) HostsMode.Whitelist -> preferences.getString("byedpi_hosts_whitelist", null)
else -> null else -> null
} }
} },
tcpFastOpen = preferences.getBoolean("byedpi_tcp_fast_open", false),
udpFakeCount = preferences.getString("byedpi_udp_fake_count", null)?.toIntOrNull(),
) )
enum class DesyncMethod { enum class DesyncMethod {

View File

@ -79,6 +79,7 @@ class ByeDpiUISettingsFragment : PreferenceFragmentCompat() {
val ttlFake = findPreferenceNotNull<EditTextPreference>("byedpi_fake_ttl") val ttlFake = findPreferenceNotNull<EditTextPreference>("byedpi_fake_ttl")
val fakeSni = findPreferenceNotNull<EditTextPreference>("byedpi_fake_sni") val fakeSni = findPreferenceNotNull<EditTextPreference>("byedpi_fake_sni")
val oobData = findPreferenceNotNull<EditTextPreference>("byedpi_oob_data") val oobData = findPreferenceNotNull<EditTextPreference>("byedpi_oob_data")
val udpFakeCount = findPreferenceNotNull<EditTextPreference>("byedpi_udp_fake_count")
val hostMixedCase = findPreferenceNotNull<CheckBoxPreference>("byedpi_host_mixed_case") val hostMixedCase = findPreferenceNotNull<CheckBoxPreference>("byedpi_host_mixed_case")
val domainMixedCase = findPreferenceNotNull<CheckBoxPreference>("byedpi_domain_mixed_case") val domainMixedCase = findPreferenceNotNull<CheckBoxPreference>("byedpi_domain_mixed_case")
val hostRemoveSpaces = val hostRemoveSpaces =
@ -105,11 +106,17 @@ class ByeDpiUISettingsFragment : PreferenceFragmentCompat() {
} }
} }
val desyncAllProtocols =
!desyncHttp.isChecked && !desyncHttps.isChecked && !desyncUdp.isChecked
if (desyncAllProtocols || desyncUdp.isChecked) {
udpFakeCount.isVisible = true
} else {
udpFakeCount.isVisible = false
}
when (desyncMethod) { when (desyncMethod) {
None -> { None -> {
desyncHttp.isVisible = false
desyncHttps.isVisible = false
desyncUdp.isVisible = false
splitPosition.isVisible = false splitPosition.isVisible = false
splitAtHost.isVisible = false splitAtHost.isVisible = false
ttlFake.isVisible = false ttlFake.isVisible = false
@ -121,15 +128,9 @@ class ByeDpiUISettingsFragment : PreferenceFragmentCompat() {
} }
else -> { else -> {
desyncHttp.isVisible = true
desyncHttps.isVisible = true
desyncUdp.isVisible = true
splitPosition.isVisible = true splitPosition.isVisible = true
splitAtHost.isVisible = true splitAtHost.isVisible = true
val desyncAllProtocols =
!desyncHttp.isChecked && !desyncHttps.isChecked && !desyncUdp.isChecked
if (desyncAllProtocols || desyncHttp.isChecked) { if (desyncAllProtocols || desyncHttp.isChecked) {
hostMixedCase.isVisible = true hostMixedCase.isVisible = true
domainMixedCase.isVisible = true domainMixedCase.isVisible = true

View File

@ -85,10 +85,18 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
val mode = findPreferenceNotNull<ListPreference>("byedpi_mode") val mode = findPreferenceNotNull<ListPreference>("byedpi_mode")
.value.let { Mode.fromString(it) } .value.let { Mode.fromString(it) }
val dns = findPreferenceNotNull<EditTextPreference>("dns_ip") val dns = findPreferenceNotNull<EditTextPreference>("dns_ip")
val ipv6 = findPreferenceNotNull<SwitchPreference>("ipv6_enable")
when (mode) { when (mode) {
Mode.VPN -> dns.isVisible = true Mode.VPN -> {
Mode.Proxy -> dns.isVisible = false dns.isVisible = true
ipv6.isVisible = true
}
Mode.Proxy -> {
dns.isVisible = false
ipv6.isVisible = false
}
} }
} }
} }

View File

@ -180,6 +180,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
val sharedPreferences = getPreferences() val sharedPreferences = getPreferences()
val port = sharedPreferences.getString("byedpi_proxy_port", null)?.toInt() ?: 1080 val port = sharedPreferences.getString("byedpi_proxy_port", null)?.toInt() ?: 1080
val dns = sharedPreferences.getStringNotNull("dns_ip", "1.1.1.1") val dns = sharedPreferences.getStringNotNull("dns_ip", "1.1.1.1")
val ipv6 = sharedPreferences.getBoolean("ipv6_enable", false)
val tun2socksConfig = """ val tun2socksConfig = """
| misc: | misc:
@ -200,13 +201,18 @@ class ByeDpiVpnService : LifecycleVpnService() {
throw e throw e
} }
val vpn = createBuilder(dns).establish() val fd = createBuilder(dns, ipv6).establish()
?: throw IllegalStateException("VPN connection failed") ?: throw IllegalStateException("VPN connection failed")
this.tunFd = vpn this.tunFd = fd
Log.d(TAG, "Native tun2socks start") TProxyService.TProxyStartService(configPath.absolutePath, fd.fd)
TProxyService.TProxyStartService(configPath.absolutePath, vpn.fd)
try {
File(cacheDir, "config.tmp").delete()
} catch (e: SecurityException) {
Log.e(TAG, "Failed to delete config file", e)
}
Log.i(TAG, "Tun2Socks started") Log.i(TAG, "Tun2Socks started")
} }
@ -215,15 +221,10 @@ class ByeDpiVpnService : LifecycleVpnService() {
Log.i(TAG, "Stopping tun2socks") Log.i(TAG, "Stopping tun2socks")
TProxyService.TProxyStopService() TProxyService.TProxyStopService()
Log.d(TAG, "Native tun2socks stopped done")
tunFd?.close() ?: Log.w(TAG, "VPN not running") tunFd?.close() ?: Log.w(TAG, "VPN not running")
tunFd = null tunFd = null
try {
File(cacheDir, "config.tmp").delete()
} catch (e: SecurityException) {
Log.e(TAG, "Failed to delete config file", e)
}
Log.i(TAG, "Tun2socks stopped") Log.i(TAG, "Tun2socks stopped")
} }
@ -268,7 +269,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
ByeDpiVpnService::class.java, ByeDpiVpnService::class.java,
) )
private fun createBuilder(dns: String): Builder { private fun createBuilder(dns: String, ipv6: Boolean): Builder {
Log.d(TAG, "DNS: $dns") Log.d(TAG, "DNS: $dns")
val builder = Builder() val builder = Builder()
builder.setSession("ByeDPI") builder.setSession("ByeDPI")
@ -282,8 +283,13 @@ class ByeDpiVpnService : LifecycleVpnService() {
) )
builder.addAddress("10.10.10.10", 32) builder.addAddress("10.10.10.10", 32)
builder.addRoute("0.0.0.0", 0) .addRoute("0.0.0.0", 0)
builder.addRoute("0:0:0:0:0:0:0:0", 0)
if (ipv6) {
builder.addAddress("fd00:::1", 128)
.addRoute("::", 0)
}
if (dns.isNotBlank()) { if (dns.isNotBlank()) {
builder.addDnsServer(dns) builder.addDnsServer(dns)
} }

View File

@ -58,4 +58,4 @@ fun createConnectionNotification(
PendingIntent.FLAG_IMMUTABLE, PendingIntent.FLAG_IMMUTABLE,
) )
) )
.build() .build()

View File

@ -3,7 +3,6 @@ package io.github.dovecoteescapee.byedpi.utility
import android.net.InetAddresses import android.net.InetAddresses
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import android.util.Patterns
import android.widget.Toast import android.widget.Toast
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
@ -12,11 +11,14 @@ private const val TAG = "ValidateUtils"
fun checkIp(ip: String): Boolean = fun checkIp(ip: String): Boolean =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
InetAddresses.isNumericAddress(ip) InetAddresses.isNumericAddress(ip) && InetAddresses.parseNumericAddress(ip).let {
!it.isAnyLocalAddress && !it.isLoopbackAddress
}
} else { } else {
// This pattern doesn't not support IPv6 // This pattern doesn't not support IPv6
@Suppress("DEPRECATION") // @Suppress("DEPRECATION")
Patterns.IP_ADDRESS.matcher(ip).matches() // Patterns.IP_ADDRESS.matcher(ip).matches()
true
} }
fun PreferenceFragmentCompat.setEditTestPreferenceListenerPort(key: String) { fun PreferenceFragmentCompat.setEditTestPreferenceListenerPort(key: String) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,24 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M14.74,16.866C17.473,15.885 17.893,13.832 17.869,12.884C17.835,11.487 16.792,10.113 16.751,9.354C16.714,8.676 16.967,8.174 18.106,8.338C18.002,8.039 17.763,7.536 17.479,7.178C17.112,6.714 16.629,6.356 15.858,6.357C14.554,6.359 14.124,7.537 13.826,8.296C13.528,9.056 13.837,9.36 13.026,10.509C13.149,11.895 13.097,11.909 12.882,12.771C12.362,14.851 10.511,17.307 9.567,18.641C8.623,19.975 7.843,20.663 8.685,21.329C9.526,21.997 9.927,21.032 10.234,20.477C10.542,19.923 10.871,19.205 11.014,19.246C11.158,19.287 11.199,19.153 10.819,20.303C10.44,21.452 10.532,21.955 11.353,22.017C12.174,22.078 12.328,21.575 12.389,20.713C12.451,19.852 12.564,19.379 12.677,19.379C12.79,19.379 12.821,19.236 12.903,20.323C12.985,21.411 13.016,22.15 14.063,21.781C15.109,21.412 14.791,20.816 14.535,20.242C14.278,19.667 14.207,19.092 14.319,19.041C14.432,18.99 14.566,19.257 14.976,19.893C15.387,20.529 15.613,21.289 16.485,20.704C17.697,19.89 16.043,18.477 15.304,17.543C13.991,18.015 13.324,18.015 13.313,17.543C13.303,17.071 13.875,17.176 14.74,16.866ZM16.057,7.078C16.282,7.078 16.465,7.261 16.465,7.486C16.465,7.71 16.282,7.893 16.057,7.893C15.833,7.893 15.65,7.71 15.65,7.486C15.65,7.261 15.833,7.078 16.057,7.078Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M12.323,10.724C12.328,12.132 12.098,13.609 10.721,15.484C9.624,15.608 8.689,15.672 8.468,15.227C8.209,14.706 8.769,14.613 9.399,14.153C9.399,14.153 10.449,13.531 10.239,13.298C10.029,13.064 8.995,13.788 8.497,13.974C7.999,14.161 7.027,14.632 6.506,13.71C6.272,13.298 6.568,13.088 7.478,12.901C8.388,12.715 8.932,12.458 8.777,12.256C8.621,12.054 7.206,12.566 6.086,12.575C4.966,12.582 4.616,12.085 4.616,11.68C4.616,11.276 4.966,11.338 5.946,11.276C6.926,11.214 7.552,11.307 7.532,10.926C7.517,10.623 6.101,10.856 5.246,10.724C4.39,10.592 3.13,10.359 3.13,9.448C3.13,9.06 3.355,8.943 4.047,9.168C4.74,9.394 6.606,9.728 6.606,9.308C6.606,8.888 4.18,9.121 2.849,7.877C1.519,6.633 2.391,5.972 2.655,5.972C3.06,5.972 3.375,6.62 5.548,7.317C6.59,7.651 9.2,7.899 9.958,8.266C10.908,8.725 12.323,10.724 12.323,10.724Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M15.828,5.51C16.435,4.323 16.575,4.112 16.837,3.281C17.099,2.449 17.249,1.729 17.696,1.762C18.302,1.806 18.524,2.519 18.273,3.392C17.982,4.402 17.146,5.458 16.94,5.776C16.605,5.468 15.828,5.51 15.828,5.51Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M17.31,5.903C18.106,5.041 18.208,4.344 18.605,4.337C19.001,4.33 19.22,4.813 19.142,5.238C19.065,5.664 18.542,6.428 18.194,6.796C17.774,6.357 17.536,6.085 17.31,5.903Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M18.47,7.222C18.552,7.004 19.051,6.733 19.283,6.946C19.573,7.212 19.602,8.025 19.036,8.586C18.852,7.943 18.61,7.396 18.47,7.222Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M18.378,11.31C18.712,11.059 19.35,10.323 19.239,9.844C19.128,9.366 19.046,9.308 18.378,9.22C17.71,9.133 17.497,9.061 17.531,9.298C17.566,9.535 18.363,11.121 18.378,11.31Z"
android:fillColor="#ffffff"/>
</vector>

View File

@ -62,4 +62,7 @@
<string name="byedpi_hosts_mode_setting">Hosts</string> <string name="byedpi_hosts_mode_setting">Hosts</string>
<string name="byedpi_hosts_blacklist_setting">Hosts blacklist</string> <string name="byedpi_hosts_blacklist_setting">Hosts blacklist</string>
<string name="byedpi_hosts_whitelist_setting">Hosts whitelist</string> <string name="byedpi_hosts_whitelist_setting">Hosts whitelist</string>
<string name="byedpi_tcp_fast_open_setting">TCP Fast Open</string>
<string name="byedpi_udp_fake_count">UDP fake count</string>
<string name="ipv6_setting">IPv6</string>
</resources> </resources>

View File

@ -75,6 +75,11 @@
android:inputType="textMultiLine" android:inputType="textMultiLine"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<CheckBoxPreference
android:key="byedpi_tcp_fast_open"
android:title="@string/byedpi_tcp_fast_open_setting"
android:defaultValue="false" />
<com.takisoft.preferencex.EditTextPreference <com.takisoft.preferencex.EditTextPreference
android:key="byedpi_default_ttl" android:key="byedpi_default_ttl"
android:title="@string/byedpi_default_ttl_setting" android:title="@string/byedpi_default_ttl_setting"
@ -109,7 +114,7 @@
android:key="byedpi_split_position" android:key="byedpi_split_position"
android:title="@string/byedpi_split_position_setting" android:title="@string/byedpi_split_position_setting"
android:inputType="numberSigned" android:inputType="numberSigned"
android:defaultValue="3" android:defaultValue="2"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<CheckBoxPreference <CheckBoxPreference
@ -136,6 +141,13 @@
android:defaultValue="a" android:defaultValue="a"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.EditTextPreference
android:key="byedpi_udp_fake_count"
android:title="@string/byedpi_udp_fake_count"
android:inputType="number"
android:defaultValue="0"
app:useSimpleSummaryProvider="true" />
<CheckBoxPreference <CheckBoxPreference
android:key="byedpi_host_mixed_case" android:key="byedpi_host_mixed_case"
android:title="@string/byedpi_host_mixed_case_setting" android:title="@string/byedpi_host_mixed_case_setting"

View File

@ -29,6 +29,11 @@
android:defaultValue="1.1.1.1" android:defaultValue="1.1.1.1"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<SwitchPreference
android:key="ipv6_enable"
android:title="@string/ipv6_setting"
android:defaultValue="false" />
</androidx.preference.PreferenceCategory> </androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory <androidx.preference.PreferenceCategory

View File

@ -0,0 +1 @@
<p><i>ByeDPI</i> runs a local VPN service to bypass DPI (Deep Packet Inspection) and censorship. It runs a SOCKS5 proxy <a href='https://github.com/hufrea/byedpi' target='_blank' rel='nofollow noopener'>ByeDPI</a> and redirects all traffic through it.</p><p>To bypass some blocks, you may need to change the settings. More about the various settings can be found in the <a href='https://github.com/hufrea/byedpi#readme-ov-file' target='_blank' rel='nofollow noopener'>ByeDPI documentation</a>.</p><p>The application uses the VPN mode on Android to redirect traffic, but does not send anything to a remote server. It does not encrypt traffic and does not hide your IP address.</p>

View File

@ -0,0 +1 @@
обход цензуры на Android