mirror of
git://f0xx.org/ac/ac-mobile-android
synced 2026-07-29 07:37:39 +03:00
Bundle iodine 0.7.0 with JNI TUN bridge; apply BE iodine credentials on connect; canonical heartbeat URL fallback. Co-authored-by: Cursor <cursoragent@cursor.com>
166 lines
4.8 KiB
C
166 lines
4.8 KiB
C
/*
|
|
* Android iodine client runner — uses VpnService TUN fd (no open_tun).
|
|
*/
|
|
#include <android/log.h>
|
|
#include <errno.h>
|
|
#include <jni.h>
|
|
#include <netdb.h>
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "client.h"
|
|
#include "common.h"
|
|
|
|
#define IODINE_LOG_TAG "IodineNative"
|
|
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, IODINE_LOG_TAG, __VA_ARGS__)
|
|
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, IODINE_LOG_TAG, __VA_ARGS__)
|
|
|
|
static pthread_t iodine_thread;
|
|
static volatile int iodine_running;
|
|
static int iodine_dns_fd = -1;
|
|
|
|
struct iodine_run_args {
|
|
int tun_fd;
|
|
char nameserv_host[256];
|
|
char topdomain[256];
|
|
char password[33];
|
|
};
|
|
|
|
static void iodine_sighandler(int sig) {
|
|
(void) sig;
|
|
client_stop();
|
|
}
|
|
|
|
static void *iodine_thread_main(void *arg) {
|
|
struct iodine_run_args *params = (struct iodine_run_args *) arg;
|
|
|
|
int tun_fd = params->tun_fd;
|
|
char *nameserv_host = params->nameserv_host;
|
|
char *topdomain = params->topdomain;
|
|
char *password = params->password;
|
|
free(params);
|
|
|
|
struct sockaddr_storage nameservaddr;
|
|
int nameservaddr_len;
|
|
int dns_fd = -1;
|
|
int retval = 1;
|
|
|
|
client_init();
|
|
client_set_selecttimeout(4);
|
|
client_set_lazymode(1);
|
|
client_set_topdomain(topdomain);
|
|
client_set_password(password);
|
|
client_set_hostname_maxlen(0xFF);
|
|
|
|
nameservaddr_len = get_addr(nameserv_host, DNS_PORT, AF_UNSPEC, 0, &nameservaddr);
|
|
if (nameservaddr_len < 0) {
|
|
ALOGW("nameserver lookup failed for %s", nameserv_host);
|
|
iodine_running = 0;
|
|
return NULL;
|
|
}
|
|
client_set_nameserver(&nameservaddr, nameservaddr_len);
|
|
|
|
dns_fd = open_dns_from_host(NULL, 0, nameservaddr.ss_family, AI_PASSIVE);
|
|
if (dns_fd < 0) {
|
|
ALOGW("open_dns_from_host failed errno=%d", errno);
|
|
iodine_running = 0;
|
|
return NULL;
|
|
}
|
|
iodine_dns_fd = dns_fd;
|
|
|
|
signal(SIGINT, iodine_sighandler);
|
|
signal(SIGTERM, iodine_sighandler);
|
|
|
|
ALOGI("iodine handshake %s via %s tun_fd=%d", topdomain, nameserv_host, tun_fd);
|
|
if (client_handshake(dns_fd, 1, 1, 3072) != 0) {
|
|
ALOGW("iodine handshake failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
ALOGI("iodine tunnel active");
|
|
iodine_running = 1;
|
|
client_tunnel(tun_fd, dns_fd);
|
|
retval = 0;
|
|
|
|
cleanup:
|
|
if (dns_fd >= 0) {
|
|
close_dns(dns_fd);
|
|
iodine_dns_fd = -1;
|
|
}
|
|
iodine_running = 0;
|
|
ALOGI("iodine thread exit retval=%d", retval);
|
|
return NULL;
|
|
}
|
|
|
|
static int start_iodine_thread(int tun_fd, const char *nameserv, const char *topdomain,
|
|
const char *password) {
|
|
if (iodine_running) {
|
|
return 0;
|
|
}
|
|
struct iodine_run_args *params = calloc(1, sizeof(*params));
|
|
if (!params) {
|
|
return -1;
|
|
}
|
|
params->tun_fd = tun_fd;
|
|
strncpy(params->nameserv_host, nameserv, sizeof(params->nameserv_host) - 1);
|
|
strncpy(params->topdomain, topdomain, sizeof(params->topdomain) - 1);
|
|
strncpy(params->password, password, sizeof(params->password) - 1);
|
|
if (pthread_create(&iodine_thread, NULL, iodine_thread_main, params) != 0) {
|
|
free(params);
|
|
return -1;
|
|
}
|
|
pthread_detach(iodine_thread);
|
|
return 0;
|
|
}
|
|
|
|
static void stop_iodine_thread(void) {
|
|
if (!iodine_running) {
|
|
return;
|
|
}
|
|
client_stop();
|
|
if (iodine_dns_fd >= 0) {
|
|
shutdown(iodine_dns_fd, SHUT_RDWR);
|
|
}
|
|
iodine_running = 0;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_com_foxx_androidcast_remoteaccess_IodineNative_start(
|
|
JNIEnv *env, jclass clazz, jint tun_fd, jstring nameserv, jstring topdomain, jstring password) {
|
|
(void) clazz;
|
|
if (tun_fd < 0 || !nameserv || !topdomain || !password) {
|
|
return JNI_FALSE;
|
|
}
|
|
const char *ns = (*env)->GetStringUTFChars(env, nameserv, NULL);
|
|
const char *td = (*env)->GetStringUTFChars(env, topdomain, NULL);
|
|
const char *pw = (*env)->GetStringUTFChars(env, password, NULL);
|
|
if (!ns || !td || !pw) {
|
|
if (ns) (*env)->ReleaseStringUTFChars(env, nameserv, ns);
|
|
if (td) (*env)->ReleaseStringUTFChars(env, topdomain, td);
|
|
if (pw) (*env)->ReleaseStringUTFChars(env, password, pw);
|
|
return JNI_FALSE;
|
|
}
|
|
int rc = start_iodine_thread((int) tun_fd, ns, td, pw);
|
|
(*env)->ReleaseStringUTFChars(env, nameserv, ns);
|
|
(*env)->ReleaseStringUTFChars(env, topdomain, td);
|
|
(*env)->ReleaseStringUTFChars(env, password, pw);
|
|
return rc == 0 ? JNI_TRUE : JNI_FALSE;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_com_foxx_androidcast_remoteaccess_IodineNative_stop(JNIEnv *env, jclass clazz) {
|
|
(void) env;
|
|
(void) clazz;
|
|
stop_iodine_thread();
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_com_foxx_androidcast_remoteaccess_IodineNative_isRunning(JNIEnv *env, jclass clazz) {
|
|
(void) env;
|
|
(void) clazz;
|
|
return iodine_running ? JNI_TRUE : JNI_FALSE;
|
|
}
|