Checkout byedpi to main branch

This commit is contained in:
dovecoteescapee 2024-03-02 14:26:08 +03:00
parent 9a46a16cc0
commit 81d080863f
6 changed files with 112 additions and 89 deletions

@ -1 +1 @@
Subproject commit 12adfe285f603bfa38c19e9057d897b2b4e40941
Subproject commit 6b484d598817cffd61344a812721fb00089f5095

View File

@ -5,7 +5,6 @@
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <sys/eventfd.h>
#include <jni.h>
#include <android/log.h>
@ -17,24 +16,15 @@ const enum demode DESYNC_METHODS[] = {
DESYNC_FAKE
};
extern int NOT_EXIT;
extern struct packet fake_tls, fake_http;
extern int get_default_ttl();
extern int get_addr(const char *str, struct sockaddr_ina *addr);
JNIEXPORT jint JNICALL
Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniEventFd(JNIEnv *env, jobject thiz) {
int fd = eventfd(0, EFD_NONBLOCK);
if (fd < 0) {
return -1;
}
return fd;
}
JNIEXPORT jint JNICALL
Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniStartProxy(
Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
JNIEnv *env,
jobject thiz,
jint event_fd,
jstring ip,
jint port,
jint max_connections,
@ -87,22 +77,33 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniStartProxy(
}
}
int res = listener(event_fd, s);
if (close(event_fd) < 0) {
uniperror("close");
int fd = listen_socket(&s);
if (fd < 0) {
uniperror("listen_socket");
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
Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniStopProxy(JNIEnv *env, jobject thiz,
jint event_fd) {
if (eventfd_write(event_fd, 1) < 0) {
uniperror("eventfd_write");
LOG(LOG_S, "event_fd: %d", event_fd);
jint fd) {
LOG(LOG_S, "stop_proxy, fd: %d", fd);
if (shutdown(fd, SHUT_RDWR) < 0) {
return get_e();
}
return 0;
}

View File

@ -1,5 +1,7 @@
package io.github.dovecoteescapee.byedpi.core
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.io.IOException
class ByeDpiProxy {
@ -9,42 +11,61 @@ class ByeDpiProxy {
}
}
private val fd = jniEventFd()
private val mutex = Mutex()
private var fd = -1
init {
if (fd < 0) {
throw IOException("Failed to create eventfd")
suspend fun startProxy(preferences: ByeDpiProxyPreferences): Int =
jniStartProxy(createSocket(preferences))
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 =
jniStartProxy(
eventFd = fd,
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 suspend fun createSocket(preferences: ByeDpiProxyPreferences): Int =
mutex.withLock {
if (fd >= 0) {
throw IllegalStateException("Proxy is already running")
}
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(
eventFd: Int,
this.fd = fd
fd
}
private external fun jniCreateSocket(
ip: String,
port: Int,
maxConnections: Int,
@ -64,5 +85,7 @@ class ByeDpiProxy {
tlsRecordSplitAtSni: Boolean,
): Int
private external fun jniStopProxy(eventFd: Int): Int
private external fun jniStartProxy(fd: Int): Int
private external fun jniStopProxy(fd: Int): Int
}

View File

@ -41,25 +41,23 @@ class ByeDpiProxyPreferences(
constructor(preferences: SharedPreferences) : this(
ip = preferences.getString("byedpi_proxy_ip", null),
port = preferences.getString("byedpi_proxy_port", null)?.toInt(),
maxConnections = preferences.getString("byedpi_max_connections", null)?.toInt(),
bufferSize = preferences.getString("byedpi_buffer_size", null)?.toInt(),
defaultTtl = preferences.getString("byedpi_default_ttl", null)?.toInt(),
port = preferences.getString("byedpi_proxy_port", null)?.toIntOrNull(),
maxConnections = preferences.getString("byedpi_max_connections", null)?.toIntOrNull(),
bufferSize = preferences.getString("byedpi_buffer_size", null)?.toIntOrNull(),
defaultTtl = preferences.getString("byedpi_default_ttl", null)?.toIntOrNull(),
noDomain = preferences.getBoolean("byedpi_no_domain", false),
desyncKnown = preferences.getBoolean("byedpi_desync_known", false),
desyncMethod = preferences.getString("byedpi_desync_method", null)
?.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),
fakeTtl = preferences.getString("byedpi_fake_ttl", null)?.toInt(),
fakeTtl = preferences.getString("byedpi_fake_ttl", null)?.toIntOrNull(),
hostMixedCase = preferences.getBoolean("byedpi_host_mixed_case", false),
domainMixedCase = preferences.getBoolean("byedpi_domain_mixed_case", false),
hostRemoveSpaces = preferences.getBoolean("byedpi_host_remove_spaces", 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),
)
enum class DesyncMethod {

View File

@ -24,11 +24,14 @@ import io.github.dovecoteescapee.byedpi.utility.registerNotificationChannel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
class ByeDpiProxyService : LifecycleService() {
private var proxy: ByeDpiProxy? = null
private var proxy = ByeDpiProxy()
private var proxyJob: Job? = null
private val mutex = Mutex()
companion object {
private val TAG: String = ByeDpiProxyService::class.java.simpleName
@ -77,7 +80,9 @@ class ByeDpiProxyService : LifecycleService() {
}
try {
startProxy()
mutex.withLock {
startProxy()
}
updateStatus(ServiceStatus.CONNECTED)
startForeground()
} catch (e: Exception) {
@ -103,7 +108,9 @@ class ByeDpiProxyService : LifecycleService() {
private suspend fun stop() {
Log.i(TAG, "Stopping VPN")
stopProxy()
mutex.withLock {
stopProxy()
}
updateStatus(ServiceStatus.DISCONNECTED)
stopSelf()
}
@ -111,7 +118,7 @@ class ByeDpiProxyService : LifecycleService() {
private suspend fun startProxy() {
Log.i(TAG, "Starting proxy")
if (proxy != null || proxyJob != null) {
if (proxyJob != null) {
Log.w(TAG, "Proxy fields not null")
throw IllegalStateException("Proxy fields not null")
}
@ -120,7 +127,7 @@ class ByeDpiProxyService : LifecycleService() {
val preferences = getByeDpiPreferences()
proxyJob = lifecycleScope.launch(Dispatchers.IO) {
val code = proxy?.startProxy(preferences)
val code = proxy.startProxy(preferences)
withContext(Dispatchers.Main) {
if (code != 0) {
@ -141,13 +148,12 @@ class ByeDpiProxyService : LifecycleService() {
if (status == ServiceStatus.DISCONNECTED) {
Log.w(TAG, "Proxy already disconnected")
return
} else {
proxy?.stopProxy()
proxyJob?.join()
proxy = null
proxyJob = null
}
proxy.stopProxy()
proxyJob?.join()
proxyJob = null
Log.i(TAG, "Proxy stopped")
}

View File

@ -29,17 +29,15 @@ import io.github.dovecoteescapee.byedpi.utility.registerNotificationChannel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
class ByeDpiVpnService : LifecycleVpnService() {
private var proxy: ByeDpiProxy? = null
private val proxy = ByeDpiProxy()
private var proxyJob: Job? = null
private var vpn: ParcelFileDescriptor? = null
private val semaphore = Semaphore(1)
@Volatile
private val mutex = Mutex()
private var stopping: Boolean = false
companion object {
@ -94,7 +92,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
}
try {
semaphore.withPermit {
mutex.withLock {
startProxy()
startTun2Socks()
}
@ -123,8 +121,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
private suspend fun stop() {
Log.i(TAG, "Stopping")
// Wait end of starting
semaphore.withPermit {
mutex.withLock {
stopping = true
try {
stopTun2Socks()
@ -143,16 +140,15 @@ class ByeDpiVpnService : LifecycleVpnService() {
private suspend fun startProxy() {
Log.i(TAG, "Starting proxy")
if (proxy != null || proxyJob != null) {
if (proxyJob != null) {
Log.w(TAG, "Proxy fields not null")
throw IllegalStateException("Proxy fields not null")
}
proxy = ByeDpiProxy()
val preferences = getByeDpiPreferences()
proxyJob = lifecycleScope.launch(Dispatchers.IO) {
val code = proxy?.startProxy(preferences)
val code = proxy.startProxy(preferences)
withContext(Dispatchers.Main) {
if (code != 0) {
@ -176,13 +172,12 @@ class ByeDpiVpnService : LifecycleVpnService() {
if (status == ServiceStatus.DISCONNECTED) {
Log.w(TAG, "Proxy already disconnected")
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")
}