mirror of
https://github.com/dovecoteescapee/ByeDPIAndroid.git
synced 2025-07-09 15:25:01 +00:00
Checkout byedpi to main branch
This commit is contained in:
parent
9a46a16cc0
commit
81d080863f
@ -1 +1 @@
|
|||||||
Subproject commit 12adfe285f603bfa38c19e9057d897b2b4e40941
|
Subproject commit 6b484d598817cffd61344a812721fb00089f5095
|
@ -5,7 +5,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <sys/eventfd.h>
|
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
@ -17,24 +16,15 @@ const enum demode DESYNC_METHODS[] = {
|
|||||||
DESYNC_FAKE
|
DESYNC_FAKE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern int NOT_EXIT;
|
||||||
extern struct packet fake_tls, fake_http;
|
extern struct packet fake_tls, fake_http;
|
||||||
extern int get_default_ttl();
|
extern int get_default_ttl();
|
||||||
extern int get_addr(const char *str, struct sockaddr_ina *addr);
|
extern int get_addr(const char *str, struct sockaddr_ina *addr);
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniEventFd(JNIEnv *env, jobject thiz) {
|
Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
|
||||||
int fd = eventfd(0, EFD_NONBLOCK);
|
|
||||||
if (fd < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
|
||||||
Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniStartProxy(
|
|
||||||
JNIEnv *env,
|
JNIEnv *env,
|
||||||
jobject thiz,
|
jobject thiz,
|
||||||
jint event_fd,
|
|
||||||
jstring ip,
|
jstring ip,
|
||||||
jint port,
|
jint port,
|
||||||
jint max_connections,
|
jint max_connections,
|
||||||
@ -87,22 +77,33 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniStartProxy(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = listener(event_fd, s);
|
int fd = listen_socket(&s);
|
||||||
|
if (fd < 0) {
|
||||||
if (close(event_fd) < 0) {
|
uniperror("listen_socket");
|
||||||
uniperror("close");
|
return get_e();
|
||||||
}
|
}
|
||||||
|
|
||||||
return res < 0 ? get_e() : 0;
|
LOG(LOG_S, "listen_socket, fd: %d", fd);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniStartProxy(JNIEnv *env, jobject thiz,
|
||||||
|
jint fd) {
|
||||||
|
LOG(LOG_S, "start_proxy, fd: %d", fd);
|
||||||
|
NOT_EXIT = 1;
|
||||||
|
if (event_loop(fd) < 0) {
|
||||||
|
return get_e();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniStopProxy(JNIEnv *env, jobject thiz,
|
Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniStopProxy(JNIEnv *env, jobject thiz,
|
||||||
jint event_fd) {
|
jint fd) {
|
||||||
if (eventfd_write(event_fd, 1) < 0) {
|
LOG(LOG_S, "stop_proxy, fd: %d", fd);
|
||||||
uniperror("eventfd_write");
|
if (shutdown(fd, SHUT_RDWR) < 0) {
|
||||||
LOG(LOG_S, "event_fd: %d", event_fd);
|
return get_e();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package io.github.dovecoteescapee.byedpi.core
|
package io.github.dovecoteescapee.byedpi.core
|
||||||
|
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
class ByeDpiProxy {
|
class ByeDpiProxy {
|
||||||
@ -9,42 +11,61 @@ class ByeDpiProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val fd = jniEventFd()
|
private val mutex = Mutex()
|
||||||
|
private var fd = -1
|
||||||
|
|
||||||
init {
|
suspend fun startProxy(preferences: ByeDpiProxyPreferences): Int =
|
||||||
if (fd < 0) {
|
jniStartProxy(createSocket(preferences))
|
||||||
throw IOException("Failed to create eventfd")
|
|
||||||
|
suspend fun stopProxy(): Int {
|
||||||
|
mutex.withLock {
|
||||||
|
if (fd < 0) {
|
||||||
|
throw IllegalStateException("Proxy is not running")
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = jniStopProxy(fd)
|
||||||
|
if (result == 0) {
|
||||||
|
fd = -1
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startProxy(preferences: ByeDpiProxyPreferences): Int =
|
private suspend fun createSocket(preferences: ByeDpiProxyPreferences): Int =
|
||||||
jniStartProxy(
|
mutex.withLock {
|
||||||
eventFd = fd,
|
if (fd >= 0) {
|
||||||
ip = preferences.ip,
|
throw IllegalStateException("Proxy is already running")
|
||||||
port = preferences.port,
|
}
|
||||||
maxConnections = preferences.maxConnections,
|
|
||||||
bufferSize = preferences.bufferSize,
|
|
||||||
defaultTtl = preferences.defaultTtl,
|
|
||||||
noDomain = preferences.noDomain,
|
|
||||||
desyncKnown = preferences.desyncKnown,
|
|
||||||
desyncMethod = preferences.desyncMethod.ordinal,
|
|
||||||
splitPosition = preferences.splitPosition,
|
|
||||||
splitAtHost = preferences.splitAtHost,
|
|
||||||
fakeTtl = preferences.fakeTtl,
|
|
||||||
hostMixedCase = preferences.hostMixedCase,
|
|
||||||
domainMixedCase = preferences.domainMixedCase,
|
|
||||||
hostRemoveSpaces = preferences.hostRemoveSpaces,
|
|
||||||
tlsRecordSplit = preferences.tlsRecordSplit,
|
|
||||||
tlsRecordSplitPosition = preferences.tlsRecordSplitPosition,
|
|
||||||
tlsRecordSplitAtSni = preferences.tlsRecordSplitAtSni,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun stopProxy(): Int = jniStopProxy(fd)
|
val fd = jniCreateSocket(
|
||||||
|
ip = preferences.ip,
|
||||||
|
port = preferences.port,
|
||||||
|
maxConnections = preferences.maxConnections,
|
||||||
|
bufferSize = preferences.bufferSize,
|
||||||
|
defaultTtl = preferences.defaultTtl,
|
||||||
|
noDomain = preferences.noDomain,
|
||||||
|
desyncKnown = preferences.desyncKnown,
|
||||||
|
desyncMethod = preferences.desyncMethod.ordinal,
|
||||||
|
splitPosition = preferences.splitPosition,
|
||||||
|
splitAtHost = preferences.splitAtHost,
|
||||||
|
fakeTtl = preferences.fakeTtl,
|
||||||
|
hostMixedCase = preferences.hostMixedCase,
|
||||||
|
domainMixedCase = preferences.domainMixedCase,
|
||||||
|
hostRemoveSpaces = preferences.hostRemoveSpaces,
|
||||||
|
tlsRecordSplit = preferences.tlsRecordSplit,
|
||||||
|
tlsRecordSplitPosition = preferences.tlsRecordSplitPosition,
|
||||||
|
tlsRecordSplitAtSni = preferences.tlsRecordSplitAtSni,
|
||||||
|
)
|
||||||
|
|
||||||
private external fun jniEventFd(): Int
|
if (fd < 0) {
|
||||||
|
throw IOException("Failed to create socket")
|
||||||
|
}
|
||||||
|
|
||||||
private external fun jniStartProxy(
|
this.fd = fd
|
||||||
eventFd: Int,
|
fd
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun jniCreateSocket(
|
||||||
ip: String,
|
ip: String,
|
||||||
port: Int,
|
port: Int,
|
||||||
maxConnections: Int,
|
maxConnections: Int,
|
||||||
@ -64,5 +85,7 @@ class ByeDpiProxy {
|
|||||||
tlsRecordSplitAtSni: Boolean,
|
tlsRecordSplitAtSni: Boolean,
|
||||||
): Int
|
): Int
|
||||||
|
|
||||||
private external fun jniStopProxy(eventFd: Int): Int
|
private external fun jniStartProxy(fd: Int): Int
|
||||||
|
|
||||||
|
private external fun jniStopProxy(fd: Int): Int
|
||||||
}
|
}
|
@ -41,25 +41,23 @@ class ByeDpiProxyPreferences(
|
|||||||
|
|
||||||
constructor(preferences: SharedPreferences) : this(
|
constructor(preferences: SharedPreferences) : this(
|
||||||
ip = preferences.getString("byedpi_proxy_ip", null),
|
ip = preferences.getString("byedpi_proxy_ip", null),
|
||||||
port = preferences.getString("byedpi_proxy_port", null)?.toInt(),
|
port = preferences.getString("byedpi_proxy_port", null)?.toIntOrNull(),
|
||||||
maxConnections = preferences.getString("byedpi_max_connections", null)?.toInt(),
|
maxConnections = preferences.getString("byedpi_max_connections", null)?.toIntOrNull(),
|
||||||
bufferSize = preferences.getString("byedpi_buffer_size", null)?.toInt(),
|
bufferSize = preferences.getString("byedpi_buffer_size", null)?.toIntOrNull(),
|
||||||
defaultTtl = preferences.getString("byedpi_default_ttl", null)?.toInt(),
|
defaultTtl = preferences.getString("byedpi_default_ttl", null)?.toIntOrNull(),
|
||||||
noDomain = preferences.getBoolean("byedpi_no_domain", false),
|
noDomain = preferences.getBoolean("byedpi_no_domain", false),
|
||||||
desyncKnown = preferences.getBoolean("byedpi_desync_known", false),
|
desyncKnown = preferences.getBoolean("byedpi_desync_known", false),
|
||||||
desyncMethod = preferences.getString("byedpi_desync_method", null)
|
desyncMethod = preferences.getString("byedpi_desync_method", null)
|
||||||
?.let { DesyncMethod.fromName(it) },
|
?.let { DesyncMethod.fromName(it) },
|
||||||
splitPosition = preferences.getString("byedpi_split_position", null)?.toInt(),
|
splitPosition = preferences.getString("byedpi_split_position", null)?.toIntOrNull(),
|
||||||
splitAtHost = preferences.getBoolean("byedpi_split_at_host", false),
|
splitAtHost = preferences.getBoolean("byedpi_split_at_host", false),
|
||||||
fakeTtl = preferences.getString("byedpi_fake_ttl", null)?.toInt(),
|
fakeTtl = preferences.getString("byedpi_fake_ttl", null)?.toIntOrNull(),
|
||||||
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),
|
||||||
tlsRecordSplit = preferences.getBoolean("byedpi_tlsrec_enabled", false),
|
tlsRecordSplit = preferences.getBoolean("byedpi_tlsrec_enabled", false),
|
||||||
tlsRecordSplitPosition = preferences.getString("byedpi_tlsrec_position", null)?.toInt(),
|
tlsRecordSplitPosition = preferences.getString("byedpi_tlsrec_position", null)?.toIntOrNull(),
|
||||||
tlsRecordSplitAtSni = preferences.getBoolean("byedpi_tlsrec_at_sni", false),
|
tlsRecordSplitAtSni = preferences.getBoolean("byedpi_tlsrec_at_sni", false),
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class DesyncMethod {
|
enum class DesyncMethod {
|
||||||
|
@ -24,11 +24,14 @@ import io.github.dovecoteescapee.byedpi.utility.registerNotificationChannel
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class ByeDpiProxyService : LifecycleService() {
|
class ByeDpiProxyService : LifecycleService() {
|
||||||
private var proxy: ByeDpiProxy? = null
|
private var proxy = ByeDpiProxy()
|
||||||
private var proxyJob: Job? = null
|
private var proxyJob: Job? = null
|
||||||
|
private val mutex = Mutex()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TAG: String = ByeDpiProxyService::class.java.simpleName
|
private val TAG: String = ByeDpiProxyService::class.java.simpleName
|
||||||
@ -77,7 +80,9 @@ class ByeDpiProxyService : LifecycleService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
startProxy()
|
mutex.withLock {
|
||||||
|
startProxy()
|
||||||
|
}
|
||||||
updateStatus(ServiceStatus.CONNECTED)
|
updateStatus(ServiceStatus.CONNECTED)
|
||||||
startForeground()
|
startForeground()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@ -103,7 +108,9 @@ class ByeDpiProxyService : LifecycleService() {
|
|||||||
private suspend fun stop() {
|
private suspend fun stop() {
|
||||||
Log.i(TAG, "Stopping VPN")
|
Log.i(TAG, "Stopping VPN")
|
||||||
|
|
||||||
stopProxy()
|
mutex.withLock {
|
||||||
|
stopProxy()
|
||||||
|
}
|
||||||
updateStatus(ServiceStatus.DISCONNECTED)
|
updateStatus(ServiceStatus.DISCONNECTED)
|
||||||
stopSelf()
|
stopSelf()
|
||||||
}
|
}
|
||||||
@ -111,7 +118,7 @@ class ByeDpiProxyService : LifecycleService() {
|
|||||||
private suspend fun startProxy() {
|
private suspend fun startProxy() {
|
||||||
Log.i(TAG, "Starting proxy")
|
Log.i(TAG, "Starting proxy")
|
||||||
|
|
||||||
if (proxy != null || proxyJob != null) {
|
if (proxyJob != null) {
|
||||||
Log.w(TAG, "Proxy fields not null")
|
Log.w(TAG, "Proxy fields not null")
|
||||||
throw IllegalStateException("Proxy fields not null")
|
throw IllegalStateException("Proxy fields not null")
|
||||||
}
|
}
|
||||||
@ -120,7 +127,7 @@ class ByeDpiProxyService : LifecycleService() {
|
|||||||
val preferences = getByeDpiPreferences()
|
val preferences = getByeDpiPreferences()
|
||||||
|
|
||||||
proxyJob = lifecycleScope.launch(Dispatchers.IO) {
|
proxyJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val code = proxy?.startProxy(preferences)
|
val code = proxy.startProxy(preferences)
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
if (code != 0) {
|
if (code != 0) {
|
||||||
@ -141,13 +148,12 @@ class ByeDpiProxyService : LifecycleService() {
|
|||||||
if (status == ServiceStatus.DISCONNECTED) {
|
if (status == ServiceStatus.DISCONNECTED) {
|
||||||
Log.w(TAG, "Proxy already disconnected")
|
Log.w(TAG, "Proxy already disconnected")
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
proxy?.stopProxy()
|
|
||||||
proxyJob?.join()
|
|
||||||
proxy = null
|
|
||||||
proxyJob = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proxy.stopProxy()
|
||||||
|
proxyJob?.join()
|
||||||
|
proxyJob = null
|
||||||
|
|
||||||
Log.i(TAG, "Proxy stopped")
|
Log.i(TAG, "Proxy stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,17 +29,15 @@ import io.github.dovecoteescapee.byedpi.utility.registerNotificationChannel
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Semaphore
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withPermit
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class ByeDpiVpnService : LifecycleVpnService() {
|
class ByeDpiVpnService : LifecycleVpnService() {
|
||||||
private var proxy: ByeDpiProxy? = null
|
private val proxy = ByeDpiProxy()
|
||||||
private var proxyJob: Job? = null
|
private var proxyJob: Job? = null
|
||||||
private var vpn: ParcelFileDescriptor? = null
|
private var vpn: ParcelFileDescriptor? = null
|
||||||
private val semaphore = Semaphore(1)
|
private val mutex = Mutex()
|
||||||
|
|
||||||
@Volatile
|
|
||||||
private var stopping: Boolean = false
|
private var stopping: Boolean = false
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -94,7 +92,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
semaphore.withPermit {
|
mutex.withLock {
|
||||||
startProxy()
|
startProxy()
|
||||||
startTun2Socks()
|
startTun2Socks()
|
||||||
}
|
}
|
||||||
@ -123,8 +121,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
|
|||||||
private suspend fun stop() {
|
private suspend fun stop() {
|
||||||
Log.i(TAG, "Stopping")
|
Log.i(TAG, "Stopping")
|
||||||
|
|
||||||
// Wait end of starting
|
mutex.withLock {
|
||||||
semaphore.withPermit {
|
|
||||||
stopping = true
|
stopping = true
|
||||||
try {
|
try {
|
||||||
stopTun2Socks()
|
stopTun2Socks()
|
||||||
@ -143,16 +140,15 @@ class ByeDpiVpnService : LifecycleVpnService() {
|
|||||||
private suspend fun startProxy() {
|
private suspend fun startProxy() {
|
||||||
Log.i(TAG, "Starting proxy")
|
Log.i(TAG, "Starting proxy")
|
||||||
|
|
||||||
if (proxy != null || proxyJob != null) {
|
if (proxyJob != null) {
|
||||||
Log.w(TAG, "Proxy fields not null")
|
Log.w(TAG, "Proxy fields not null")
|
||||||
throw IllegalStateException("Proxy fields not null")
|
throw IllegalStateException("Proxy fields not null")
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy = ByeDpiProxy()
|
|
||||||
val preferences = getByeDpiPreferences()
|
val preferences = getByeDpiPreferences()
|
||||||
|
|
||||||
proxyJob = lifecycleScope.launch(Dispatchers.IO) {
|
proxyJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val code = proxy?.startProxy(preferences)
|
val code = proxy.startProxy(preferences)
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
if (code != 0) {
|
if (code != 0) {
|
||||||
@ -176,13 +172,12 @@ class ByeDpiVpnService : LifecycleVpnService() {
|
|||||||
if (status == ServiceStatus.DISCONNECTED) {
|
if (status == ServiceStatus.DISCONNECTED) {
|
||||||
Log.w(TAG, "Proxy already disconnected")
|
Log.w(TAG, "Proxy already disconnected")
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
proxy?.stopProxy() ?: throw IllegalStateException("Proxy field null")
|
|
||||||
proxyJob?.join() ?: throw IllegalStateException("ProxyJob field null")
|
|
||||||
proxy = null
|
|
||||||
proxyJob = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proxy.stopProxy()
|
||||||
|
proxyJob?.join() ?: throw IllegalStateException("ProxyJob field null")
|
||||||
|
proxyJob = null
|
||||||
|
|
||||||
Log.i(TAG, "Proxy stopped")
|
Log.i(TAG, "Proxy stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user