Improvements and fixes (v 1.2.0):

- Update ByeDPI to versions v0.13
- Added new options to UI editor
- Structured UI editor
- Changed default split position to 1
- Fixed listen ip validation
This commit is contained in:
dovecoteescapee 2024-08-23 18:22:09 +03:00
parent 9a6254869d
commit c95be6eb91
18 changed files with 212 additions and 172 deletions

View File

@ -29,7 +29,7 @@ height="80">](https://apt.izzysoft.de/fdroid/index/apk/io.github.dovecoteescapee
## Настройки ## Настройки
Для обхода некоторых блокировок может потребоваться изменить настройки. Подробнее о различных настройках можно прочитать в [документации ByeDPI](https://github.com/hufrea/byedpi/tree/v0.12#readme). Для обхода некоторых блокировок может потребоваться изменить настройки. Подробнее о различных настройках можно прочитать в [документации ByeDPI](https://github.com/hufrea/byedpi/blob/v0.13/README.md).
## FAQ ## FAQ

View File

@ -30,7 +30,7 @@ This application runs a SOCKS5 proxy [ByeDPI](https://github.com/hufrea/byedpi)
## Settings ## Settings
To bypass some blocks, you may need to change the settings. More about the various settings can be found in the [ByeDPI documentation](https://github.com/hufrea/byedpi/tree/v0.12#readme). To bypass some blocks, you may need to change the settings. More about the various settings can be found in the [ByeDPI documentation](https://github.com/hufrea/byedpi/blob/v0.13/README.md).
## FAQ ## FAQ

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 = 9 versionCode = 10
versionName = "1.1.1" versionName = "1.2.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

@ -1 +1 @@
Subproject commit dcf5ed727c996d0073a6cb95d5eec45a793d28a2 Subproject commit 078842b084853bc30f33eaaec7acc510cf67e560

View File

@ -13,7 +13,10 @@ void clear_params(void);
char *ftob(const char *str, ssize_t *sl); char *ftob(const char *str, ssize_t *sl);
char *parse_cform(const char *str, ssize_t *size); char *data_from_str(const char *str, ssize_t *size);
size_t parse_cform(char *buffer, size_t blen,
const char *str, size_t slen);
struct mphdr *parse_hosts(char *buffer, size_t size); struct mphdr *parse_hosts(char *buffer, size_t size);

View File

@ -17,6 +17,7 @@ const enum demode DESYNC_METHODS[] = {
DESYNC_DISORDER, DESYNC_DISORDER,
DESYNC_FAKE, DESYNC_FAKE,
DESYNC_OOB, DESYNC_OOB,
DESYNC_DISOOB,
}; };
enum hosts_mode { enum hosts_mode {
@ -81,7 +82,7 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
jboolean split_at_host, jboolean split_at_host,
jint fake_ttl, jint fake_ttl,
jstring fake_sni, jstring fake_sni,
jstring custom_oob_data, jbyte custom_oob_char,
jboolean host_mixed_case, jboolean host_mixed_case,
jboolean domain_mixed_case, jboolean domain_mixed_case,
jboolean host_remove_spaces, jboolean host_remove_spaces,
@ -91,7 +92,9 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
jint hosts_mode, jint hosts_mode,
jstring hosts, jstring hosts,
jboolean tfo, jboolean tfo,
jint udp_fake_count) { jint udp_fake_count,
jboolean drop_sack,
jint fake_offset) {
struct sockaddr_ina s; struct sockaddr_ina s;
const char *address = (*env)->GetStringUTFChars(env, ip, 0); const char *address = (*env)->GetStringUTFChars(env, ip, 0);
@ -135,7 +138,7 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
} }
const char *str = (*env)->GetStringUTFChars(env, hosts, 0); const char *str = (*env)->GetStringUTFChars(env, hosts, 0);
dp->file_ptr = parse_cform(str, &dp->file_size); dp->file_ptr = data_from_str(str, &dp->file_size);
(*env)->ReleaseStringUTFChars(env, hosts, str); (*env)->ReleaseStringUTFChars(env, hosts, str);
dp->hosts = parse_hosts(dp->file_ptr, dp->file_size); dp->hosts = parse_hosts(dp->file_ptr, dp->file_size);
if (!dp->hosts) { if (!dp->hosts) {
@ -158,7 +161,7 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
if (hosts_mode == HOSTS_BLACKLIST) { if (hosts_mode == HOSTS_BLACKLIST) {
const char *str = (*env)->GetStringUTFChars(env, hosts, 0); const char *str = (*env)->GetStringUTFChars(env, hosts, 0);
dp->file_ptr = parse_cform(str, &dp->file_size); dp->file_ptr = data_from_str(str, &dp->file_size);
(*env)->ReleaseStringUTFChars(env, hosts, str); (*env)->ReleaseStringUTFChars(env, hosts, str);
dp->hosts = parse_hosts(dp->file_ptr, dp->file_size); dp->hosts = parse_hosts(dp->file_ptr, dp->file_size);
if (!dp->hosts) { if (!dp->hosts) {
@ -170,6 +173,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->udp_fake_count = udp_fake_count;
dp->drop_sack = drop_sack;
dp->proto = dp->proto =
IS_HTTP * desync_http | IS_HTTP * desync_http |
IS_HTTPS * desync_https | IS_HTTPS * desync_https |
@ -216,6 +220,8 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
} }
if (mode == DESYNC_FAKE) { if (mode == DESYNC_FAKE) {
dp->fake_offset = fake_offset;
const char *sni = (*env)->GetStringUTFChars(env, fake_sni, 0); const char *sni = (*env)->GetStringUTFChars(env, fake_sni, 0);
LOG(LOG_S, "fake_sni: %s", sni); LOG(LOG_S, "fake_sni: %s", sni);
res = change_tls_sni(sni, fake_tls.data, fake_tls.size); res = change_tls_sni(sni, fake_tls.data, fake_tls.size);
@ -227,17 +233,8 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
} }
if (mode == DESYNC_OOB) { if (mode == DESYNC_OOB) {
const char *oob = (*env)->GetStringUTFChars(env, custom_oob_data, 0); dp->oob_char[0] = custom_oob_char;
const size_t oob_len = strlen(oob); dp->oob_char[1] = 1;
oob_data.size = oob_len;
oob_data.data = malloc(oob_len);
if (oob_data.data == NULL) {
uniperror("malloc");
return -1;
}
memcpy(oob_data.data, oob, oob_len);
(*env)->ReleaseStringUTFChars(env, custom_oob_data, oob);
} }
if (dp->proto) { if (dp->proto) {

View File

@ -15,9 +15,10 @@ void reset_params(void) {
params = default_params; params = default_params;
} }
extern const struct option options[35]; extern const struct option options[38];
int parse_args(int argc, char **argv) { int parse_args(int argc, char **argv)
{
int optc = sizeof(options)/sizeof(*options); int optc = sizeof(options)/sizeof(*options);
for (int i = 0, e = optc; i < e; i++) for (int i = 0, e = optc; i < e; i++)
optc += options[i].has_arg; optc += options[i].has_arg;
@ -50,8 +51,9 @@ int parse_args(int argc, char **argv) {
optind = optreset = 1; optind = optreset = 1;
while (!invalid && (rez = getopt_long_only( while (!invalid && (rez = getopt_long(
argc, argv, opt, options, 0)) != -1) { argc, argv, opt, options, 0)) != -1) {
switch (rez) { switch (rez) {
case 'N': case 'N':
@ -64,6 +66,15 @@ int parse_args(int argc, char **argv) {
params.udp = 0; params.udp = 0;
break; break;
// case 'h':
// printf(help_text);
// reset_params();
// return 0;
// case 'v':
// printf("%s\n", VERSION);
// reset_params();
// return 0;
case 'i': case 'i':
if (get_addr(optarg, if (get_addr(optarg,
(struct sockaddr_ina *)&params.laddr) < 0) (struct sockaddr_ina *)&params.laddr) < 0)
@ -119,10 +130,6 @@ int parse_args(int argc, char **argv) {
reset_params(); reset_params();
return -1; return -1;
} }
if (!optarg) {
dp->detect |= DETECT_TORST;
break;
}
end = optarg; end = optarg;
while (end && !invalid) { while (end && !invalid) {
switch (*end) { switch (*end) {
@ -132,14 +139,9 @@ int parse_args(int argc, char **argv) {
case 'r': case 'r':
dp->detect |= DETECT_HTTP_LOCAT; dp->detect |= DETECT_HTTP_LOCAT;
break; break;
case 'c':
dp->detect |= DETECT_HTTP_CLERR;
break;
case 's':
dp->detect |= DETECT_TLS_INVSID;
break;
case 'a': case 'a':
dp->detect |= DETECT_TLS_ALERT; case 's':
dp->detect |= DETECT_TLS_ERR;
break; break;
case 'n': case 'n':
break; break;
@ -161,8 +163,12 @@ int parse_args(int argc, char **argv) {
break; break;
case 'T':; case 'T':;
#ifdef __linux__
float f = strtof(optarg, &end); float f = strtof(optarg, &end);
val = (long)(f * 1000); val = (long)(f * 1000);
#else
val = strtol(optarg, &end, 0);
#endif
if (val <= 0 || val > UINT_MAX || *end) if (val <= 0 || val > UINT_MAX || *end)
invalid = 1; invalid = 1;
else else
@ -212,6 +218,7 @@ int parse_args(int argc, char **argv) {
case 's': case 's':
case 'd': case 'd':
case 'o': case 'o':
case 'q':
case 'f': case 'f':
; ;
struct part *part = add((void *)&dp->parts, struct part *part = add((void *)&dp->parts,
@ -231,6 +238,8 @@ int parse_args(int argc, char **argv) {
break; break;
case 'o': part->m = DESYNC_OOB; case 'o': part->m = DESYNC_OOB;
break; break;
case 'q': part->m = DESYNC_DISOOB;
break;
case 'f': part->m = DESYNC_FAKE; case 'f': part->m = DESYNC_FAKE;
} }
break; break;
@ -263,13 +272,21 @@ int parse_args(int argc, char **argv) {
dp->md5sig = 1; dp->md5sig = 1;
break; break;
case 'O':
val = strtol(optarg, &end, 0);
if (val <= 0 || *end)
invalid = 1;
else
dp->fake_offset = val;
break;
case 'n': case 'n':
if (change_tls_sni(optarg, fake_tls.data, fake_tls.size)) { if (change_tls_sni(optarg, fake_tls.data, fake_tls.size)) {
fprintf(stderr, "error chsni\n"); perror("change_tls_sni");
reset_params(); reset_params();
return -1; return -1;
} }
printf("sni: %s\n", optarg); LOG(LOG_S, "sni: %s", optarg);
break; break;
case 'l': case 'l':
@ -284,14 +301,11 @@ int parse_args(int argc, char **argv) {
break; break;
case 'e': case 'e':
if (oob_data.data != oob_char) { val = parse_cform(dp->oob_char, 1, optarg, strlen(optarg));
continue; if (val != 1) {
}
oob_data.data = ftob(optarg, &oob_data.size);
if (!oob_data.data) {
uniperror("read/parse");
invalid = 1; invalid = 1;
} }
else dp->oob_char[1] = 1;
break; break;
case 'M': case 'M':
@ -366,6 +380,10 @@ int parse_args(int argc, char **argv) {
} }
break; break;
case 'Y':
dp->drop_sack = 1;
break;
case 'w': // case 'w': //
params.sfdelay = strtol(optarg, &end, 0); params.sfdelay = strtol(optarg, &end, 0);
if (params.sfdelay < 0 || optarg == end if (params.sfdelay < 0 || optarg == end
@ -376,9 +394,11 @@ int parse_args(int argc, char **argv) {
case 'W': case 'W':
params.wait_send = 0; params.wait_send = 0;
break; break;
#ifdef __linux__
case 'P': case 'P':
params.protect_path = optarg; params.protect_path = optarg;
break; break;
#endif
case 0: case 0:
break; break;
@ -387,13 +407,13 @@ int parse_args(int argc, char **argv) {
return -1; return -1;
default: default:
printf("?: %c\n", rez); LOG(LOG_S, "Unknown option: -%c", rez);
reset_params(); reset_params();
return -1; return -1;
} }
} }
if (invalid) { if (invalid) {
fprintf(stderr, "invalid value: -%c %s\n", rez, optarg); LOG(LOG_S, "invalid value: -%c %s", rez, optarg);
reset_params(); reset_params();
return -1; return -1;
} }

View File

@ -69,7 +69,7 @@ class ByeDpiProxy {
splitAtHost = preferences.splitAtHost, splitAtHost = preferences.splitAtHost,
fakeTtl = preferences.fakeTtl, fakeTtl = preferences.fakeTtl,
fakeSni = preferences.fakeSni, fakeSni = preferences.fakeSni,
oobData = preferences.oobData, oobChar = preferences.oobChar,
hostMixedCase = preferences.hostMixedCase, hostMixedCase = preferences.hostMixedCase,
domainMixedCase = preferences.domainMixedCase, domainMixedCase = preferences.domainMixedCase,
hostRemoveSpaces = preferences.hostRemoveSpaces, hostRemoveSpaces = preferences.hostRemoveSpaces,
@ -80,6 +80,8 @@ class ByeDpiProxy {
hosts = preferences.hosts, hosts = preferences.hosts,
tcpFastOpen = preferences.tcpFastOpen, tcpFastOpen = preferences.tcpFastOpen,
udpFakeCount = preferences.udpFakeCount, udpFakeCount = preferences.udpFakeCount,
dropSack = preferences.dropSack,
fakeOffset = preferences.fakeOffset,
) )
} }
@ -101,7 +103,7 @@ class ByeDpiProxy {
splitAtHost: Boolean, splitAtHost: Boolean,
fakeTtl: Int, fakeTtl: Int,
fakeSni: String, fakeSni: String,
oobData: String, oobChar: Byte,
hostMixedCase: Boolean, hostMixedCase: Boolean,
domainMixedCase: Boolean, domainMixedCase: Boolean,
hostRemoveSpaces: Boolean, hostRemoveSpaces: Boolean,
@ -112,6 +114,8 @@ class ByeDpiProxy {
hosts: String?, hosts: String?,
tcpFastOpen: Boolean, tcpFastOpen: Boolean,
udpFakeCount: Int, udpFakeCount: Int,
dropSack: Boolean,
fakeOffset: Int,
): Int ): Int
private external fun jniStartProxy(fd: Int): Int private external fun jniStartProxy(fd: Int): Int

View File

@ -48,7 +48,7 @@ class ByeDpiProxyUIPreferences(
splitAtHost: Boolean? = null, splitAtHost: Boolean? = null,
fakeTtl: Int? = null, fakeTtl: Int? = null,
fakeSni: String? = null, fakeSni: String? = null,
oobData: String? = null, oobChar: String? = null,
hostMixedCase: Boolean? = null, hostMixedCase: Boolean? = null,
domainMixedCase: Boolean? = null, domainMixedCase: Boolean? = null,
hostRemoveSpaces: Boolean? = null, hostRemoveSpaces: Boolean? = null,
@ -59,6 +59,8 @@ class ByeDpiProxyUIPreferences(
hosts: String? = null, hosts: String? = null,
tcpFastOpen: Boolean? = null, tcpFastOpen: Boolean? = null,
udpFakeCount: Int? = null, udpFakeCount: Int? = null,
dropSack: Boolean? = null,
byedpiFakeOffset: 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
@ -71,11 +73,11 @@ 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 ?: 2 val splitPosition: Int = splitPosition ?: 1
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"
val oobData: String = oobData ?: "a" val oobChar: Byte = (oobChar ?: "a")[0].code.toByte()
val hostMixedCase: Boolean = hostMixedCase ?: false val hostMixedCase: Boolean = hostMixedCase ?: false
val domainMixedCase: Boolean = domainMixedCase ?: false val domainMixedCase: Boolean = domainMixedCase ?: false
val hostRemoveSpaces: Boolean = hostRemoveSpaces ?: false val hostRemoveSpaces: Boolean = hostRemoveSpaces ?: false
@ -90,6 +92,8 @@ class ByeDpiProxyUIPreferences(
else hosts?.trim() else hosts?.trim()
val tcpFastOpen: Boolean = tcpFastOpen ?: false val tcpFastOpen: Boolean = tcpFastOpen ?: false
val udpFakeCount: Int = udpFakeCount ?: 0 val udpFakeCount: Int = udpFakeCount ?: 0
val dropSack: Boolean = dropSack ?: false
val fakeOffset: Int = byedpiFakeOffset ?: 0
constructor(preferences: SharedPreferences) : this( constructor(preferences: SharedPreferences) : this(
ip = preferences.getString("byedpi_proxy_ip", null), ip = preferences.getString("byedpi_proxy_ip", null),
@ -107,7 +111,7 @@ class ByeDpiProxyUIPreferences(
splitAtHost = preferences.getBoolean("byedpi_split_at_host", false), splitAtHost = preferences.getBoolean("byedpi_split_at_host", false),
fakeTtl = preferences.getString("byedpi_fake_ttl", null)?.toIntOrNull(), fakeTtl = preferences.getString("byedpi_fake_ttl", null)?.toIntOrNull(),
fakeSni = preferences.getString("byedpi_fake_sni", null), fakeSni = preferences.getString("byedpi_fake_sni", null),
oobData = preferences.getString("byedpi_oob_data", null), oobChar = preferences.getString("byedpi_oob_data", null),
hostMixedCase = preferences.getBoolean("byedpi_host_mixed_case", false), hostMixedCase = preferences.getBoolean("byedpi_host_mixed_case", false),
domainMixedCase = preferences.getBoolean("byedpi_domain_mixed_case", false), domainMixedCase = preferences.getBoolean("byedpi_domain_mixed_case", false),
hostRemoveSpaces = preferences.getBoolean("byedpi_host_remove_spaces", false), hostRemoveSpaces = preferences.getBoolean("byedpi_host_remove_spaces", false),
@ -126,6 +130,8 @@ class ByeDpiProxyUIPreferences(
}, },
tcpFastOpen = preferences.getBoolean("byedpi_tcp_fast_open", false), tcpFastOpen = preferences.getBoolean("byedpi_tcp_fast_open", false),
udpFakeCount = preferences.getString("byedpi_udp_fake_count", null)?.toIntOrNull(), udpFakeCount = preferences.getString("byedpi_udp_fake_count", null)?.toIntOrNull(),
dropSack = preferences.getBoolean("byedpi_drop_sack", false),
byedpiFakeOffset = preferences.getString("byedpi_fake_offset", null)?.toIntOrNull(),
) )
enum class DesyncMethod { enum class DesyncMethod {
@ -133,7 +139,8 @@ class ByeDpiProxyUIPreferences(
Split, Split,
Disorder, Disorder,
Fake, Fake,
OOB; OOB,
DISOOB;
companion object { companion object {
fun fromName(name: String): DesyncMethod { fun fromName(name: String): DesyncMethod {
@ -143,6 +150,7 @@ class ByeDpiProxyUIPreferences(
"disorder" -> Disorder "disorder" -> Disorder
"fake" -> Fake "fake" -> Fake
"oob" -> OOB "oob" -> OOB
"disoob" -> DISOOB
else -> throw IllegalArgumentException("Unknown desync method: $name") else -> throw IllegalArgumentException("Unknown desync method: $name")
} }
} }

View File

@ -78,7 +78,8 @@ class ByeDpiUISettingsFragment : PreferenceFragmentCompat() {
val splitAtHost = findPreferenceNotNull<CheckBoxPreference>("byedpi_split_at_host") val splitAtHost = findPreferenceNotNull<CheckBoxPreference>("byedpi_split_at_host")
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 fakeOffset = findPreferenceNotNull<EditTextPreference>("byedpi_fake_offset")
val oobChar = findPreferenceNotNull<EditTextPreference>("byedpi_oob_data")
val udpFakeCount = findPreferenceNotNull<EditTextPreference>("byedpi_udp_fake_count") 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")
@ -89,81 +90,36 @@ class ByeDpiUISettingsFragment : PreferenceFragmentCompat() {
findPreferenceNotNull<EditTextPreference>("byedpi_tlsrec_position") findPreferenceNotNull<EditTextPreference>("byedpi_tlsrec_position")
val splitTlsRecAtSni = findPreferenceNotNull<CheckBoxPreference>("byedpi_tlsrec_at_sni") val splitTlsRecAtSni = findPreferenceNotNull<CheckBoxPreference>("byedpi_tlsrec_at_sni")
when (hostsMode) { hostsBlacklist.isVisible = hostsMode == Blacklist
Disable -> { hostsWhitelist.isVisible = hostsMode == Whitelist
hostsBlacklist.isVisible = false
hostsWhitelist.isVisible = false
}
Blacklist -> { val desyncEnabled = desyncMethod != None
hostsBlacklist.isVisible = true splitPosition.isVisible = desyncEnabled
hostsWhitelist.isVisible = false splitAtHost.isVisible = desyncEnabled
}
Whitelist -> { val isFake = desyncMethod == Fake
hostsBlacklist.isVisible = false ttlFake.isVisible = isFake
hostsWhitelist.isVisible = true fakeSni.isVisible = isFake
} fakeOffset.isVisible = isFake
}
val isOob = desyncMethod == OOB || desyncMethod == DISOOB
oobChar.isVisible = isOob
val desyncAllProtocols = val desyncAllProtocols =
!desyncHttp.isChecked && !desyncHttps.isChecked && !desyncUdp.isChecked !desyncHttp.isChecked && !desyncHttps.isChecked && !desyncUdp.isChecked
if (desyncAllProtocols || desyncUdp.isChecked) { val desyncHttpEnabled = desyncAllProtocols || desyncHttp.isChecked
udpFakeCount.isVisible = true hostMixedCase.isEnabled = desyncHttpEnabled
} else { domainMixedCase.isEnabled = desyncHttpEnabled
udpFakeCount.isVisible = false hostRemoveSpaces.isEnabled = desyncHttpEnabled
}
when (desyncMethod) { val desyncUdpEnabled = desyncAllProtocols || desyncUdp.isChecked
None -> { udpFakeCount.isEnabled = desyncUdpEnabled
splitPosition.isVisible = false
splitAtHost.isVisible = false
ttlFake.isVisible = false
fakeSni.isVisible = false
oobData.isVisible = false
hostMixedCase.isVisible = false
domainMixedCase.isVisible = false
hostRemoveSpaces.isVisible = false
}
else -> { val desyncHttpsEnabled = desyncAllProtocols || desyncHttps.isChecked
splitPosition.isVisible = true splitTlsRec.isEnabled = desyncHttpsEnabled
splitAtHost.isVisible = true val tlsRecEnabled = desyncHttpsEnabled && splitTlsRec.isChecked
splitTlsRecPosition.isEnabled = tlsRecEnabled
if (desyncAllProtocols || desyncHttp.isChecked) { splitTlsRecAtSni.isEnabled = tlsRecEnabled
hostMixedCase.isVisible = true
domainMixedCase.isVisible = true
hostRemoveSpaces.isVisible = true
} else {
hostMixedCase.isVisible = false
domainMixedCase.isVisible = false
hostRemoveSpaces.isVisible = false
}
when (desyncMethod) {
Fake -> {
ttlFake.isVisible = true
fakeSni.isVisible = true
oobData.isVisible = false
}
OOB -> {
ttlFake.isVisible = false
fakeSni.isVisible = false
oobData.isVisible = true
}
else -> {
ttlFake.isVisible = false
fakeSni.isVisible = false
oobData.isVisible = false
}
}
}
}
splitTlsRecPosition.isVisible = splitTlsRec.isChecked
splitTlsRecAtSni.isVisible = splitTlsRec.isChecked
} }
} }

View File

@ -39,7 +39,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
setPreferencesFromResource(R.xml.main_settings, rootKey) setPreferencesFromResource(R.xml.main_settings, rootKey)
setEditTextPreferenceListener("dns_ip") { setEditTextPreferenceListener("dns_ip") {
it.isBlank() || checkIp(it) it.isBlank() || checkNotLocalIp(it)
} }
findPreferenceNotNull<DropDownPreference>("app_theme") findPreferenceNotNull<DropDownPreference>("app_theme")

View File

@ -208,12 +208,6 @@ class ByeDpiVpnService : LifecycleVpnService() {
TProxyService.TProxyStartService(configPath.absolutePath, fd.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") Log.i(TAG, "Tun2Socks started")
} }
@ -222,6 +216,12 @@ class ByeDpiVpnService : LifecycleVpnService() {
TProxyService.TProxyStopService() TProxyService.TProxyStopService()
try {
File(cacheDir, "config.tmp").delete()
} catch (e: SecurityException) {
Log.e(TAG, "Failed to delete config file", e)
}
tunFd?.close() ?: Log.w(TAG, "VPN not running") tunFd?.close() ?: Log.w(TAG, "VPN not running")
tunFd = null tunFd = null

View File

@ -10,6 +10,16 @@ import androidx.preference.PreferenceFragmentCompat
private const val TAG = "ValidateUtils" private const val TAG = "ValidateUtils"
fun checkIp(ip: String): Boolean = fun checkIp(ip: String): Boolean =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
InetAddresses.isNumericAddress(ip)
} else {
// This pattern doesn't not support IPv6
// @Suppress("DEPRECATION")
// Patterns.IP_ADDRESS.matcher(ip).matches()
true
}
fun checkNotLocalIp(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.parseNumericAddress(ip).let { InetAddresses.isNumericAddress(ip) && InetAddresses.parseNumericAddress(ip).let {
!it.isAnyLocalAddress && !it.isLoopbackAddress !it.isAnyLocalAddress && !it.isLoopbackAddress

View File

@ -26,6 +26,7 @@
<item name="disorder">Disorder</item> <item name="disorder">Disorder</item>
<item name="fake">Fake</item> <item name="fake">Fake</item>
<item name="oob">Out-of-band</item> <item name="oob">Out-of-band</item>
<item name="oob">Disordered out-of-band</item>
</array> </array>
<array name="byedpi_desync_methods_entries"> <array name="byedpi_desync_methods_entries">
<item name="none">none</item> <item name="none">none</item>
@ -33,6 +34,7 @@
<item name="disorder">disorder</item> <item name="disorder">disorder</item>
<item name="fake">fake</item> <item name="fake">fake</item>
<item name="oob">oob</item> <item name="oob">oob</item>
<item name="oob">disoob</item>
</array> </array>
<array name="byedpi_hosts_modes"> <array name="byedpi_hosts_modes">

View File

@ -1,5 +1,5 @@
<resources> <resources>
<string name="byedpi_docs">https://github.com/hufrea/byedpi/tree/v0.12#readme</string> <string name="byedpi_docs">https://github.com/hufrea/byedpi/blob/v0.13/README.md</string>
<string name="app_name">ByeDPI</string> <string name="app_name">ByeDPI</string>
<string name="vpn_connect">Connect</string> <string name="vpn_connect">Connect</string>
<string name="vpn_disconnect">Disconnect</string> <string name="vpn_disconnect">Disconnect</string>
@ -65,4 +65,11 @@
<string name="byedpi_tcp_fast_open_setting">TCP Fast Open</string> <string name="byedpi_tcp_fast_open_setting">TCP Fast Open</string>
<string name="byedpi_udp_fake_count">UDP fake count</string> <string name="byedpi_udp_fake_count">UDP fake count</string>
<string name="ipv6_setting">IPv6</string> <string name="ipv6_setting">IPv6</string>
<string name="byedpi_fake_offset_setting">Fake offset</string>
<string name="byedpi_drop_sack_setting">Drop SACK</string>
<string name="desync_udp_category">UDP</string>
<string name="desync_http_category">HTTP</string>
<string name="desync_https_category">HTTPS</string>
<string name="byedpi_protocols_category">Protocols</string>
<string name="byedpi_protocols_hint">Uncheck all to desync all traffic</string>
</resources> </resources>

View File

@ -48,6 +48,11 @@
android:title="@string/byedpi_no_domain_setting" android:title="@string/byedpi_no_domain_setting"
android:defaultValue="false" /> android:defaultValue="false" />
<CheckBoxPreference
android:key="byedpi_tcp_fast_open"
android:title="@string/byedpi_tcp_fast_open_setting"
android:defaultValue="false" />
</androidx.preference.PreferenceCategory> </androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory <androidx.preference.PreferenceCategory
@ -75,11 +80,6 @@
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"
@ -95,6 +95,55 @@
android:defaultValue="disorder" android:defaultValue="disorder"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.EditTextPreference
android:key="byedpi_split_position"
android:title="@string/byedpi_split_position_setting"
android:inputType="numberSigned"
android:defaultValue="1"
app:useSimpleSummaryProvider="true" />
<CheckBoxPreference
android:key="byedpi_split_at_host"
android:title="@string/byedpi_split_at_host_setting"
android:defaultValue="false" />
<CheckBoxPreference
android:key="byedpi_drop_sack"
android:title="@string/byedpi_drop_sack_setting"
android:defaultValue="false" />
<com.takisoft.preferencex.EditTextPreference
android:key="byedpi_fake_ttl"
android:title="@string/byedpi_fake_ttl_setting"
android:inputType="number"
android:defaultValue="8"
app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.EditTextPreference
android:key="byedpi_fake_offset"
android:title="@string/byedpi_fake_offset_setting"
android:inputType="number"
android:defaultValue="0"
app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.EditTextPreference
android:key="byedpi_fake_sni"
android:title="@string/sni_of_fake_packet"
android:defaultValue="www.iana.org"
app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.EditTextPreference
android:key="byedpi_oob_data"
android:title="@string/oob_data"
android:defaultValue="a"
app:useSimpleSummaryProvider="true" />
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory
android:title="@string/byedpi_protocols_category"
android:summary="@string/byedpi_protocols_hint">
<CheckBoxPreference <CheckBoxPreference
android:key="byedpi_desync_http" android:key="byedpi_desync_http"
android:title="@string/desync_http" android:title="@string/desync_http"
@ -110,43 +159,10 @@
android:title="@string/desync_udp" android:title="@string/desync_udp"
android:defaultValue="false" /> android:defaultValue="false" />
<com.takisoft.preferencex.EditTextPreference </androidx.preference.PreferenceCategory>
android:key="byedpi_split_position"
android:title="@string/byedpi_split_position_setting"
android:inputType="numberSigned"
android:defaultValue="2"
app:useSimpleSummaryProvider="true" />
<CheckBoxPreference <androidx.preference.PreferenceCategory
android:key="byedpi_split_at_host" android:title="@string/desync_http_category">
android:title="@string/byedpi_split_at_host_setting"
android:defaultValue="false" />
<com.takisoft.preferencex.EditTextPreference
android:key="byedpi_fake_ttl"
android:title="@string/byedpi_fake_ttl_setting"
android:inputType="number"
android:defaultValue="8"
app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.EditTextPreference
android:key="byedpi_fake_sni"
android:title="@string/sni_of_fake_packet"
android:defaultValue="www.iana.org"
app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.EditTextPreference
android:key="byedpi_oob_data"
android:title="@string/oob_data"
android:defaultValue="a"
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"
@ -163,6 +179,11 @@
android:title="@string/byedpi_host_remove_spaces_setting" android:title="@string/byedpi_host_remove_spaces_setting"
android:defaultValue="false"/> android:defaultValue="false"/>
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory
android:title="@string/desync_https_category">
<CheckBoxPreference <CheckBoxPreference
android:key="byedpi_tlsrec_enabled" android:key="byedpi_tlsrec_enabled"
android:title="@string/byedpi_tlsrec_enabled_setting" android:title="@string/byedpi_tlsrec_enabled_setting"
@ -182,4 +203,16 @@
</androidx.preference.PreferenceCategory> </androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory
android:title="@string/desync_udp_category">
<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" />
</androidx.preference.PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View File

@ -1 +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> <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/blob/main/README.md' 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

@ -1 +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> <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/blob/main/README.md' 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>