diff --git a/.github/images/preview.png b/.github/images/preview.png
deleted file mode 100644
index 64ca2fd..0000000
Binary files a/.github/images/preview.png and /dev/null differ
diff --git a/.github/images/screenshot1.png b/.github/images/screenshot1.png
deleted file mode 100644
index 59d9c2d..0000000
Binary files a/.github/images/screenshot1.png and /dev/null differ
diff --git a/.github/images/screenshot2.png b/.github/images/screenshot2.png
deleted file mode 100644
index 2455879..0000000
Binary files a/.github/images/screenshot2.png and /dev/null differ
diff --git a/.github/images/screenshot3.png b/.github/images/screenshot3.png
deleted file mode 100644
index a51a254..0000000
Binary files a/.github/images/screenshot3.png and /dev/null differ
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index bb0d160..330c540 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -11,8 +11,8 @@ android {
applicationId = "io.github.dovecoteescapee.byedpi"
minSdk = 21
targetSdk = 34
- versionCode = 8
- versionName = "1.1.0"
+ versionCode = 9
+ versionName = "1.1.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
diff --git a/app/src/main/cpp/native-lib.c b/app/src/main/cpp/native-lib.c
index eceb14c..e615a0c 100644
--- a/app/src/main/cpp/native-lib.c
+++ b/app/src/main/cpp/native-lib.c
@@ -89,7 +89,9 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
jint tls_record_split_position,
jboolean tls_record_split_at_sni,
jint hosts_mode,
- jstring hosts) {
+ jstring hosts,
+ jboolean tfo,
+ jint udp_fake_count) {
struct sockaddr_ina s;
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.bfsize = buffer_size;
params.resolve = !no_domain;
+ params.tfo = tfo;
if (custom_ttl) {
params.def_ttl = default_ttl;
@@ -166,6 +169,7 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
}
dp->ttl = fake_ttl;
+ dp->udp_fake_count = udp_fake_count;
dp->proto =
IS_HTTP * desync_http |
IS_HTTPS * desync_https |
diff --git a/app/src/main/java/io/github/dovecoteescapee/byedpi/core/ByeDpiProxy.kt b/app/src/main/java/io/github/dovecoteescapee/byedpi/core/ByeDpiProxy.kt
index ec069c3..db78011 100644
--- a/app/src/main/java/io/github/dovecoteescapee/byedpi/core/ByeDpiProxy.kt
+++ b/app/src/main/java/io/github/dovecoteescapee/byedpi/core/ByeDpiProxy.kt
@@ -77,7 +77,9 @@ class ByeDpiProxy {
tlsRecordSplitPosition = preferences.tlsRecordSplitPosition,
tlsRecordSplitAtSni = preferences.tlsRecordSplitAtSni,
hostsMode = preferences.hostsMode.ordinal,
- hosts = preferences.hosts
+ hosts = preferences.hosts,
+ tcpFastOpen = preferences.tcpFastOpen,
+ udpFakeCount = preferences.udpFakeCount,
)
}
@@ -107,7 +109,9 @@ class ByeDpiProxy {
tlsRecordSplitPosition: Int,
tlsRecordSplitAtSni: Boolean,
hostsMode: Int,
- hosts: String?
+ hosts: String?,
+ tcpFastOpen: Boolean,
+ udpFakeCount: Int,
): Int
private external fun jniStartProxy(fd: Int): Int
diff --git a/app/src/main/java/io/github/dovecoteescapee/byedpi/core/ByeDpiProxyPreferences.kt b/app/src/main/java/io/github/dovecoteescapee/byedpi/core/ByeDpiProxyPreferences.kt
index 59c0c3e..3f2b17d 100644
--- a/app/src/main/java/io/github/dovecoteescapee/byedpi/core/ByeDpiProxyPreferences.kt
+++ b/app/src/main/java/io/github/dovecoteescapee/byedpi/core/ByeDpiProxyPreferences.kt
@@ -57,6 +57,8 @@ class ByeDpiProxyUIPreferences(
tlsRecordSplitAtSni: Boolean? = null,
hostsMode: HostsMode? = null,
hosts: String? = null,
+ tcpFastOpen: Boolean? = null,
+ udpFakeCount: Int? = null,
) : ByeDpiProxyPreferences {
val ip: String = ip ?: "127.0.0.1"
val port: Int = port ?: 1080
@@ -69,7 +71,7 @@ class ByeDpiProxyUIPreferences(
val desyncHttps: Boolean = desyncHttps ?: true
val desyncUdp: Boolean = desyncUdp ?: false
val desyncMethod: DesyncMethod = desyncMethod ?: DesyncMethod.Disorder
- val splitPosition: Int = splitPosition ?: 3
+ val splitPosition: Int = splitPosition ?: 2
val splitAtHost: Boolean = splitAtHost ?: false
val fakeTtl: Int = fakeTtl ?: 8
val fakeSni: String = fakeSni ?: "www.iana.org"
@@ -86,6 +88,8 @@ class ByeDpiProxyUIPreferences(
val hosts: String? =
if (this.hostsMode == HostsMode.Disable) null
else hosts?.trim()
+ val tcpFastOpen: Boolean = tcpFastOpen ?: false
+ val udpFakeCount: Int = udpFakeCount ?: 0
constructor(preferences: SharedPreferences) : this(
ip = preferences.getString("byedpi_proxy_ip", null),
@@ -119,7 +123,9 @@ class ByeDpiProxyUIPreferences(
HostsMode.Whitelist -> preferences.getString("byedpi_hosts_whitelist", null)
else -> null
}
- }
+ },
+ tcpFastOpen = preferences.getBoolean("byedpi_tcp_fast_open", false),
+ udpFakeCount = preferences.getString("byedpi_udp_fake_count", null)?.toIntOrNull(),
)
enum class DesyncMethod {
diff --git a/app/src/main/java/io/github/dovecoteescapee/byedpi/fragments/ByeDpiUISettingsFragment.kt b/app/src/main/java/io/github/dovecoteescapee/byedpi/fragments/ByeDpiUISettingsFragment.kt
index 3b9e88c..ae68339 100644
--- a/app/src/main/java/io/github/dovecoteescapee/byedpi/fragments/ByeDpiUISettingsFragment.kt
+++ b/app/src/main/java/io/github/dovecoteescapee/byedpi/fragments/ByeDpiUISettingsFragment.kt
@@ -79,6 +79,7 @@ class ByeDpiUISettingsFragment : PreferenceFragmentCompat() {
val ttlFake = findPreferenceNotNull("byedpi_fake_ttl")
val fakeSni = findPreferenceNotNull("byedpi_fake_sni")
val oobData = findPreferenceNotNull("byedpi_oob_data")
+ val udpFakeCount = findPreferenceNotNull("byedpi_udp_fake_count")
val hostMixedCase = findPreferenceNotNull("byedpi_host_mixed_case")
val domainMixedCase = findPreferenceNotNull("byedpi_domain_mixed_case")
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) {
None -> {
- desyncHttp.isVisible = false
- desyncHttps.isVisible = false
- desyncUdp.isVisible = false
splitPosition.isVisible = false
splitAtHost.isVisible = false
ttlFake.isVisible = false
@@ -121,15 +128,9 @@ class ByeDpiUISettingsFragment : PreferenceFragmentCompat() {
}
else -> {
- desyncHttp.isVisible = true
- desyncHttps.isVisible = true
- desyncUdp.isVisible = true
splitPosition.isVisible = true
splitAtHost.isVisible = true
- val desyncAllProtocols =
- !desyncHttp.isChecked && !desyncHttps.isChecked && !desyncUdp.isChecked
-
if (desyncAllProtocols || desyncHttp.isChecked) {
hostMixedCase.isVisible = true
domainMixedCase.isVisible = true
diff --git a/app/src/main/java/io/github/dovecoteescapee/byedpi/fragments/MainSettingsFragment.kt b/app/src/main/java/io/github/dovecoteescapee/byedpi/fragments/MainSettingsFragment.kt
index 150e04e..4aa5bf2 100644
--- a/app/src/main/java/io/github/dovecoteescapee/byedpi/fragments/MainSettingsFragment.kt
+++ b/app/src/main/java/io/github/dovecoteescapee/byedpi/fragments/MainSettingsFragment.kt
@@ -85,10 +85,18 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
val mode = findPreferenceNotNull("byedpi_mode")
.value.let { Mode.fromString(it) }
val dns = findPreferenceNotNull("dns_ip")
+ val ipv6 = findPreferenceNotNull("ipv6_enable")
when (mode) {
- Mode.VPN -> dns.isVisible = true
- Mode.Proxy -> dns.isVisible = false
+ Mode.VPN -> {
+ dns.isVisible = true
+ ipv6.isVisible = true
+ }
+
+ Mode.Proxy -> {
+ dns.isVisible = false
+ ipv6.isVisible = false
+ }
}
}
}
diff --git a/app/src/main/java/io/github/dovecoteescapee/byedpi/services/ByeDpiVpnService.kt b/app/src/main/java/io/github/dovecoteescapee/byedpi/services/ByeDpiVpnService.kt
index 1fedb18..ed7ff34 100644
--- a/app/src/main/java/io/github/dovecoteescapee/byedpi/services/ByeDpiVpnService.kt
+++ b/app/src/main/java/io/github/dovecoteescapee/byedpi/services/ByeDpiVpnService.kt
@@ -180,6 +180,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
val sharedPreferences = getPreferences()
val port = sharedPreferences.getString("byedpi_proxy_port", null)?.toInt() ?: 1080
val dns = sharedPreferences.getStringNotNull("dns_ip", "1.1.1.1")
+ val ipv6 = sharedPreferences.getBoolean("ipv6_enable", false)
val tun2socksConfig = """
| misc:
@@ -200,13 +201,18 @@ class ByeDpiVpnService : LifecycleVpnService() {
throw e
}
- val vpn = createBuilder(dns).establish()
+ val fd = createBuilder(dns, ipv6).establish()
?: throw IllegalStateException("VPN connection failed")
- this.tunFd = vpn
+ this.tunFd = fd
- Log.d(TAG, "Native tun2socks start")
- TProxyService.TProxyStartService(configPath.absolutePath, vpn.fd)
+ TProxyService.TProxyStartService(configPath.absolutePath, fd.fd)
+
+ try {
+ File(cacheDir, "config.tmp").delete()
+ } catch (e: SecurityException) {
+ Log.e(TAG, "Failed to delete config file", e)
+ }
Log.i(TAG, "Tun2Socks started")
}
@@ -215,15 +221,10 @@ class ByeDpiVpnService : LifecycleVpnService() {
Log.i(TAG, "Stopping tun2socks")
TProxyService.TProxyStopService()
- Log.d(TAG, "Native tun2socks stopped done")
tunFd?.close() ?: Log.w(TAG, "VPN not running")
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")
}
@@ -268,7 +269,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
ByeDpiVpnService::class.java,
)
- private fun createBuilder(dns: String): Builder {
+ private fun createBuilder(dns: String, ipv6: Boolean): Builder {
Log.d(TAG, "DNS: $dns")
val builder = Builder()
builder.setSession("ByeDPI")
@@ -282,8 +283,13 @@ class ByeDpiVpnService : LifecycleVpnService() {
)
builder.addAddress("10.10.10.10", 32)
- builder.addRoute("0.0.0.0", 0)
- builder.addRoute("0:0:0:0:0:0:0:0", 0)
+ .addRoute("0.0.0.0", 0)
+
+ if (ipv6) {
+ builder.addAddress("fd00:::1", 128)
+ .addRoute("::", 0)
+ }
+
if (dns.isNotBlank()) {
builder.addDnsServer(dns)
}
diff --git a/app/src/main/java/io/github/dovecoteescapee/byedpi/utility/NotificationUtils.kt b/app/src/main/java/io/github/dovecoteescapee/byedpi/utility/NotificationUtils.kt
index 4ec01ae..af613e8 100644
--- a/app/src/main/java/io/github/dovecoteescapee/byedpi/utility/NotificationUtils.kt
+++ b/app/src/main/java/io/github/dovecoteescapee/byedpi/utility/NotificationUtils.kt
@@ -58,4 +58,4 @@ fun createConnectionNotification(
PendingIntent.FLAG_IMMUTABLE,
)
)
- .build()
\ No newline at end of file
+ .build()
diff --git a/app/src/main/java/io/github/dovecoteescapee/byedpi/utility/ValidateUtils.kt b/app/src/main/java/io/github/dovecoteescapee/byedpi/utility/ValidateUtils.kt
index a60929e..8ca4c2f 100644
--- a/app/src/main/java/io/github/dovecoteescapee/byedpi/utility/ValidateUtils.kt
+++ b/app/src/main/java/io/github/dovecoteescapee/byedpi/utility/ValidateUtils.kt
@@ -3,7 +3,6 @@ package io.github.dovecoteescapee.byedpi.utility
import android.net.InetAddresses
import android.os.Build
import android.util.Log
-import android.util.Patterns
import android.widget.Toast
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceFragmentCompat
@@ -12,11 +11,14 @@ private const val TAG = "ValidateUtils"
fun checkIp(ip: String): Boolean =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- InetAddresses.isNumericAddress(ip)
+ InetAddresses.isNumericAddress(ip) && InetAddresses.parseNumericAddress(ip).let {
+ !it.isAnyLocalAddress && !it.isLoopbackAddress
+ }
} else {
// This pattern doesn't not support IPv6
- @Suppress("DEPRECATION")
- Patterns.IP_ADDRESS.matcher(ip).matches()
+ // @Suppress("DEPRECATION")
+ // Patterns.IP_ADDRESS.matcher(ip).matches()
+ true
}
fun PreferenceFragmentCompat.setEditTestPreferenceListenerPort(key: String) {
diff --git a/app/src/main/res/drawable-hdpi/ic_notification.png b/app/src/main/res/drawable-hdpi/ic_notification.png
deleted file mode 100644
index 7ce6f29..0000000
Binary files a/app/src/main/res/drawable-hdpi/ic_notification.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_notification.png b/app/src/main/res/drawable-mdpi/ic_notification.png
deleted file mode 100644
index 3cbb23e..0000000
Binary files a/app/src/main/res/drawable-mdpi/ic_notification.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_notification.png b/app/src/main/res/drawable-xhdpi/ic_notification.png
deleted file mode 100644
index 36ef0ee..0000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_notification.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_notification.png b/app/src/main/res/drawable-xxhdpi/ic_notification.png
deleted file mode 100644
index bbb4a71..0000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_notification.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_notification.png b/app/src/main/res/drawable-xxxhdpi/ic_notification.png
deleted file mode 100644
index 48db59d..0000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_notification.png and /dev/null differ
diff --git a/app/src/main/res/drawable/ic_notification.xml b/app/src/main/res/drawable/ic_notification.xml
new file mode 100644
index 0000000..94b96bd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_notification.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b78c3f1..b2e4341 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -62,4 +62,7 @@
Hosts
Hosts blacklist
Hosts whitelist
+ TCP Fast Open
+ UDP fake count
+ IPv6
diff --git a/app/src/main/res/xml/byedpi_ui_settings.xml b/app/src/main/res/xml/byedpi_ui_settings.xml
index ba06ce9..ed1d2ee 100644
--- a/app/src/main/res/xml/byedpi_ui_settings.xml
+++ b/app/src/main/res/xml/byedpi_ui_settings.xml
@@ -75,6 +75,11 @@
android:inputType="textMultiLine"
app:useSimpleSummaryProvider="true" />
+
+
+
+
+
+
ByeDPI runs a local VPN service to bypass DPI (Deep Packet Inspection) and censorship. It runs a SOCKS5 proxy ByeDPI and redirects all traffic through it.
To bypass some blocks, you may need to change the settings. More about the various settings can be found in the ByeDPI documentation.
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.
\ No newline at end of file
diff --git a/fastlane/metadata/android/ru-RU/short_description.txt b/fastlane/metadata/android/ru-RU/short_description.txt
new file mode 100644
index 0000000..41f23f0
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/short_description.txt
@@ -0,0 +1 @@
+обход цензуры на Android
\ No newline at end of file