mirror of
git://f0xx.org/ac/ac-mobile-android
synced 2026-07-29 04:59:30 +03:00
Implement native iodine client and fix RA heartbeat URL resolution.
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>
This commit is contained in:
165
ndk/jni/iodine_jni.c
Normal file
165
ndk/jni/iodine_jni.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user