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) { ...@@ -55,7 +55,7 @@ abstract class LocalSocketListener(protected val tag: String) : Thread(tag) {
serverSocket.accept() serverSocket.accept()
} catch (e: IOException) { } catch (e: IOException) {
printLog(e) printLog(e)
null continue
}?.use(this::accept) }?.use(this::accept)
} }
} }
......
...@@ -80,14 +80,14 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro ...@@ -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)) 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 // 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") { thread("ProxyInstance-resolve") {
// A WAR fix for Huawei devices that UnknownHostException cannot be caught correctly // A WAR fix for Huawei devices that UnknownHostException cannot be caught correctly
try { try {
profile.host = InetAddress.getByName(profile.host).hostAddress ?: "" profile.host = InetAddress.getByName(profile.host).hostAddress ?: ""
} catch (_: UnknownHostException) { } } catch (_: UnknownHostException) { }
}.join(10 * 1000) }.join(10 * 1000)
if (!profile.host.isNumericAddress()) throw UnknownHostException() if (profile.host.parseNumericAddress() == null) throw UnknownHostException()
} }
} }
......
...@@ -31,7 +31,6 @@ import android.system.ErrnoException ...@@ -31,7 +31,6 @@ import android.system.ErrnoException
import android.system.Os import android.system.Os
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import com.github.shadowsocks.Core import com.github.shadowsocks.Core
import com.github.shadowsocks.JniHelper
import com.github.shadowsocks.VpnRequestActivity import com.github.shadowsocks.VpnRequestActivity
import com.github.shadowsocks.acl.Acl import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.core.R import com.github.shadowsocks.core.R
...@@ -185,7 +184,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -185,7 +184,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
return cmd return cmd
} }
private fun startVpn(): Int { private fun startVpn(): FileDescriptor {
val profile = data.proxy!!.profile val profile = data.proxy!!.profile
val builder = Builder() val builder = Builder()
.setConfigureIntent(Core.configureIntent(this)) .setConfigureIntent(Core.configureIntent(this))
...@@ -256,23 +255,26 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -256,23 +255,26 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
} }
data.processes.start(cmd, onRestartCallback = { data.processes.start(cmd, onRestartCallback = {
try { try {
sendFd(fd) sendFd(conn.fileDescriptor)
} catch (e: ErrnoException) { } catch (e: ErrnoException) {
stopRunner(true, e.message) stopRunner(true, e.message)
} }
}) })
return fd return conn.fileDescriptor
} }
private fun sendFd(fd: Int) { private fun sendFd(fd: FileDescriptor) {
if (fd == -1) throw IOException("Invalid fd (-1)")
var tries = 0 var tries = 0
val path = File(Core.deviceStorage.noBackupFilesDir, "sock_path").absolutePath val path = File(Core.deviceStorage.noBackupFilesDir, "sock_path").absolutePath
while (true) try { while (true) try {
Thread.sleep(50L shl tries) 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 return
} catch (e: ErrnoException) { } catch (e: IOException) {
if (tries > 5) throw e if (tries > 5) throw e
tries += 1 tries += 1
} }
......
...@@ -30,19 +30,20 @@ import android.graphics.BitmapFactory ...@@ -30,19 +30,20 @@ import android.graphics.BitmapFactory
import android.graphics.ImageDecoder import android.graphics.ImageDecoder
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.system.Os
import android.system.OsConstants
import android.util.TypedValue import android.util.TypedValue
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
import androidx.preference.Preference import androidx.preference.Preference
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.JniHelper
import java.net.InetAddress import java.net.InetAddress
import java.net.URLConnection import java.net.URLConnection
fun String.isNumericAddress() = JniHelper.parseNumericAddress(this) != null /**
fun String.parseNumericAddress(): InetAddress? { * A slightly more performant variant of InetAddress.parseNumericAddress.
val addr = JniHelper.parseNumericAddress(this) */
return if (addr == null) null else InetAddress.getByAddress(this, addr) 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 { fun parsePort(str: String?, default: Int, min: Int = 1025): Int {
val value = str?.toIntOrNull() ?: default val value = str?.toIntOrNull() ?: default
......
...@@ -311,24 +311,6 @@ LOCAL_LDLIBS := -llog ...@@ -311,24 +311,6 @@ LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_EXECUTABLE) 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 ## 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