Commit bcb94fef authored by Mygod's avatar Mygod

Remove all native code

parent 67b7a0f2
/* Shadowsocks - A shadowsocks client for Android
* Copyright (C) 2012 <max.c.lv@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* ___====-_ _-====___
* _--^^^#####// \\#####^^^--_
* _-^##########// ( ) \\##########^-_
* -############// |\^^/| \\############-
* _/############// (@::@) \\############\_
* /#############(( \\// ))#############\
* -###############\\ (oo) //###############-
* -#################\\ / VV \ //#################-
* -###################\\/ \//###################-
* _#/|##########/\######( /\ )######/\##########|\#_
* |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \|
* ` |/ V V ` V \#\| | | |/#/ V ' V V \| '
* ` ` ` ` / | | | | \ ' ' ' '
* ( | | | | )
* __\ | | | | /__
* (vvv(VVV)(VVV)vvv)
*
* HERE BE DRAGONS
*
*/
package com.github.shadowsocks;
import android.system.ErrnoException;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class JniHelper {
static {
System.loadLibrary("jni-helper");
}
public static native void sendFd(int fd, @NonNull String path) throws ErrnoException;
@Nullable
public static native byte[] parseNumericAddress(@NonNull String str);
}
......@@ -55,7 +55,7 @@ abstract class LocalSocketListener(protected val tag: String) : Thread(tag) {
serverSocket.accept()
} catch (e: IOException) {
printLog(e)
null
continue
}?.use(this::accept)
}
}
......
......@@ -80,14 +80,14 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
if (route == Acl.CUSTOM_RULES) Acl.save(Acl.CUSTOM_RULES, Acl.customRules.flatten(10))
// it's hard to resolve DNS on a specific interface so we'll do it here
if (!profile.host.isNumericAddress()) {
if (profile.host.parseNumericAddress() == null) {
thread("ProxyInstance-resolve") {
// A WAR fix for Huawei devices that UnknownHostException cannot be caught correctly
try {
profile.host = InetAddress.getByName(profile.host).hostAddress ?: ""
} catch (_: UnknownHostException) { }
}.join(10 * 1000)
if (!profile.host.isNumericAddress()) throw UnknownHostException()
if (profile.host.parseNumericAddress() == null) throw UnknownHostException()
}
}
......
......@@ -31,7 +31,6 @@ import android.system.ErrnoException
import android.system.Os
import androidx.core.content.getSystemService
import com.github.shadowsocks.Core
import com.github.shadowsocks.JniHelper
import com.github.shadowsocks.VpnRequestActivity
import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.core.R
......@@ -185,7 +184,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
return cmd
}
private fun startVpn(): Int {
private fun startVpn(): FileDescriptor {
val profile = data.proxy!!.profile
val builder = Builder()
.setConfigureIntent(Core.configureIntent(this))
......@@ -256,23 +255,26 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
}
data.processes.start(cmd, onRestartCallback = {
try {
sendFd(fd)
sendFd(conn.fileDescriptor)
} catch (e: ErrnoException) {
stopRunner(true, e.message)
}
})
return fd
return conn.fileDescriptor
}
private fun sendFd(fd: Int) {
if (fd == -1) throw IOException("Invalid fd (-1)")
private fun sendFd(fd: FileDescriptor) {
var tries = 0
val path = File(Core.deviceStorage.noBackupFilesDir, "sock_path").absolutePath
while (true) try {
Thread.sleep(50L shl tries)
JniHelper.sendFd(fd, path)
LocalSocket().use { localSocket ->
localSocket.connect(LocalSocketAddress(path, LocalSocketAddress.Namespace.FILESYSTEM))
localSocket.setFileDescriptorsForSend(arrayOf(fd))
localSocket.outputStream.write(42)
}
return
} catch (e: ErrnoException) {
} catch (e: IOException) {
if (tries > 5) throw e
tries += 1
}
......
......@@ -30,19 +30,20 @@ import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.net.Uri
import android.os.Build
import android.system.Os
import android.system.OsConstants
import android.util.TypedValue
import androidx.annotation.AttrRes
import androidx.preference.Preference
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.JniHelper
import java.net.InetAddress
import java.net.URLConnection
fun String.isNumericAddress() = JniHelper.parseNumericAddress(this) != null
fun String.parseNumericAddress(): InetAddress? {
val addr = JniHelper.parseNumericAddress(this)
return if (addr == null) null else InetAddress.getByAddress(this, addr)
}
/**
* A slightly more performant variant of InetAddress.parseNumericAddress.
*/
fun String?.parseNumericAddress(): InetAddress? =
Os.inet_pton(OsConstants.AF_INET, this) ?: Os.inet_pton(OsConstants.AF_INET6, this)
fun parsePort(str: String?, default: Int, min: Int = 1025): Int {
val value = str?.toIntOrNull() ?: default
......
......@@ -311,24 +311,6 @@ LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_EXECUTABLE)
########################################################
## jni-helper
########################################################
include $(CLEAR_VARS)
LOCAL_MODULE:= jni-helper
LOCAL_CFLAGS := -std=c++17
LOCAL_C_INCLUDES:= $(LOCAL_PATH)/libancillary
LOCAL_SRC_FILES:= jni-helper.cpp
LOCAL_STATIC_LIBRARIES := libancillary
include $(BUILD_SHARED_LIBRARY)
########################################################
## tun2socks
########################################################
......
#include "jni.h"
#include <algorithm>
#include <cerrno>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/un.h>
#include <ancillary.h>
using namespace std;
// Based on: https://android.googlesource.com/platform/libcore/+/564c7e8/luni/src/main/native/libcore_io_Linux.cpp#256
static void throwException(JNIEnv* env, jclass exceptionClass, jmethodID ctor2, const char* functionName, int error) {
jstring detailMessage = env->NewStringUTF(functionName);
if (detailMessage == nullptr) {
// Not really much we can do here. We're probably dead in the water,
// but let's try to stumble on...
env->ExceptionClear();
}
env->Throw(reinterpret_cast<jthrowable>(env->NewObject(exceptionClass, ctor2, detailMessage, error)));
env->DeleteLocalRef(detailMessage);
}
static void throwErrnoException(JNIEnv* env, const char* functionName) {
int error = errno;
static auto ErrnoException = reinterpret_cast<jclass>(env->NewGlobalRef(
env->FindClass("android/system/ErrnoException")));
static jmethodID ctor2 = env->GetMethodID(ErrnoException, "<init>", "(Ljava/lang/String;I)V");
throwException(env, ErrnoException, ctor2, functionName, error);
}
#pragma clang diagnostic ignored "-Wunused-parameter"
extern "C" {
JNIEXPORT void JNICALL
Java_com_github_shadowsocks_JniHelper_sendFd(JNIEnv *env, jclass type, jint tun_fd, jstring path) {
const char *sock_str = env->GetStringUTFChars(path, nullptr);
if (int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); fd == -1) {
throwErrnoException(env, "socket");
} else {
sockaddr_un addr { .sun_family = AF_UNIX };
strncpy(addr.sun_path, sock_str, sizeof(addr.sun_path) - 1);
if (connect(fd, (sockaddr*) &addr, sizeof(addr)) == -1) throwErrnoException(env, "connect");
else if (ancil_send_fd(fd, tun_fd)) throwErrnoException(env, "ancil_send_fd");
close(fd);
}
env->ReleaseStringUTFChars(path, sock_str);
}
JNIEXPORT jbyteArray JNICALL
Java_com_github_shadowsocks_JniHelper_parseNumericAddress(JNIEnv *env, jclass type, jstring str) {
const char *src = env->GetStringUTFChars(str, nullptr);
jbyte dst[max(sizeof(in_addr), sizeof(in6_addr))];
jbyteArray arr = nullptr;
if (inet_pton(AF_INET, src, dst) == 1) {
arr = env->NewByteArray(sizeof(in_addr));
env->SetByteArrayRegion(arr, 0, sizeof(in_addr), dst);
} else if (inet_pton(AF_INET6, src, dst) == 1) {
arr = env->NewByteArray(sizeof(in6_addr));
env->SetByteArrayRegion(arr, 0, sizeof(in6_addr), dst);
}
env->ReleaseStringUTFChars(str, src);
return arr;
}
}
/*
* This is called by the VM when the shared library is first loaded.
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
return JNI_VERSION_1_6;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment