diff --git a/build.sbt b/build.sbt index 5b66b016..9fa23552 100644 --- a/build.sbt +++ b/build.sbt @@ -12,6 +12,8 @@ compileOrder in Compile := CompileOrder.JavaThenScala ndkJavah in Android := List() +ndkBuild in Android := List() + resolvers += "JRAF" at "http://JRAF.org/static/maven/2" resolvers += "madeye private releases" at "http://madeye-maven-repository.googlecode.com/git/" diff --git a/build.sh b/build.sh new file mode 100755 index 00000000..d4bc155b --- /dev/null +++ b/build.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +function try () { +"$@" || exit -1 +} + +try pushd src/main + +# Build +try $ANDROID_NDK_HOME/ndk-build clean +try $ANDROID_NDK_HOME/ndk-build + +# copy executables +rm -rf assets/armeabi-v7a +rm -rf assets/x86 +mkdir -p assets/armeabi-v7a +mkdir -p assets/x86 +for app in pdnsd redsocks ss-local ss-tunnel +do + try mv libs/armeabi-v7a/$app assets/armeabi-v7a/ + try mv libs/x86/$app assets/x86/ +done + +try popd diff --git a/src/main/java/com/github/shadowsocks/Core.java b/src/main/java/com/github/shadowsocks/Tun2Socks.java similarity index 77% rename from src/main/java/com/github/shadowsocks/Core.java rename to src/main/java/com/github/shadowsocks/Tun2Socks.java index fad7a664..5cf9b4e6 100755 --- a/src/main/java/com/github/shadowsocks/Core.java +++ b/src/main/java/com/github/shadowsocks/Tun2Socks.java @@ -1,5 +1,5 @@ /* Shadowsocks - A shadowsocks client for Android - * Copyright (C) 2012 + * Copyright (C) 2014 * * 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 @@ -38,18 +38,11 @@ package com.github.shadowsocks; -public class Core { +public class Tun2Socks { static { - java.lang.System.loadLibrary("ss-local-jni"); - java.lang.System.loadLibrary("ss-tunnel-jni"); java.lang.System.loadLibrary("tun2socks-jni"); - java.lang.System.loadLibrary("pdnsd-jni"); - java.lang.System.loadLibrary("redsocks-jni"); } - public static native void sslocal(String[] cmd); - public static native void sstunnel(String[] cmd); - public static native void tun2socks(String[] cmd); - public static native void pdnsd(String[] cmd); - public static native void redsocks(String[] cmd); + public static native void start(String[] cmd); + public static native void stop(); } diff --git a/src/main/jni/Android.mk b/src/main/jni/Android.mk index ab34275c..e5ecf19e 100755 --- a/src/main/jni/Android.mk +++ b/src/main/jni/Android.mk @@ -120,13 +120,13 @@ REDSOCKS_SOURCES := base.c dnstc.c http-connect.c \ LOCAL_STATIC_LIBRARIES := libevent -LOCAL_MODULE := redsocks-jni -LOCAL_SRC_FILES := $(addprefix redsocks/, $(REDSOCKS_SOURCES)) main-jni.cpp -LOCAL_CFLAGS := -O2 -std=gnu99 -DREDSOCKS_JNI -I$(LOCAL_PATH)/redsocks \ +LOCAL_MODULE := redsocks +LOCAL_SRC_FILES := $(addprefix redsocks/, $(REDSOCKS_SOURCES)) +LOCAL_CFLAGS := -O2 -std=gnu99 -I$(LOCAL_PATH)/redsocks \ -I$(LOCAL_PATH)/libevent/include \ -I$(LOCAL_PATH)/libevent -include $(BUILD_SHARED_LIBRARY) +include $(BUILD_EXECUTABLE) ######################################################## ## pdnsd library @@ -134,13 +134,13 @@ include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) -PDNSD_SOURCES := $(wildcard $(LOCAL_PATH)/pdnsd/src/*.c) main-jni.cpp +PDNSD_SOURCES := $(wildcard $(LOCAL_PATH)/pdnsd/src/*.c) -LOCAL_MODULE := pdnsd-jni +LOCAL_MODULE := pdnsd LOCAL_SRC_FILES := $(PDNSD_SOURCES:$(LOCAL_PATH)/%=%) -LOCAL_CFLAGS := -Wall -O2 -DPDNSD_JNI -I$(LOCAL_PATH)/pdnsd +LOCAL_CFLAGS := -Wall -O2 -I$(LOCAL_PATH)/pdnsd -include $(BUILD_SHARED_LIBRARY) +include $(BUILD_EXECUTABLE) ######################################################## ## shadowsocks local library @@ -150,9 +150,9 @@ include $(CLEAR_VARS) SHADOWSOCKS_SOURCES := local.c cache.c udprelay.c encrypt.c utils.c json.c jconf.c acl.c -LOCAL_MODULE := ss-local-jni -LOCAL_SRC_FILES := $(addprefix shadowsocks/src/, $(SHADOWSOCKS_SOURCES)) main-jni.cpp -LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DUDPRELAY_LOCAL -DSSLOCAL_JNI \ +LOCAL_MODULE := ss-local +LOCAL_SRC_FILES := $(addprefix shadowsocks/src/, $(SHADOWSOCKS_SOURCES)) +LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DUDPRELAY_LOCAL \ -DUSE_CRYPTO_OPENSSL -DANDROID -DHAVE_CONFIG_H \ -I$(LOCAL_PATH)/libev/ \ -I$(LOCAL_PATH)/openssl/include \ @@ -163,22 +163,18 @@ LOCAL_STATIC_LIBRARIES := libev libcrypto libipset libcork LOCAL_LDLIBS := -llog -include $(BUILD_SHARED_LIBRARY) +include $(BUILD_EXECUTABLE) ######################################################## ## shadowsocks tunnel ######################################################## -######################################################## -## shadowsocks tunnel library -######################################################## - include $(CLEAR_VARS) SHADOWSOCKS_SOURCES := tunnel.c cache.c udprelay.c encrypt.c utils.c json.c jconf.c -LOCAL_MODULE := ss-tunnel-jni -LOCAL_SRC_FILES := $(addprefix shadowsocks/src/, $(SHADOWSOCKS_SOURCES)) main-jni.cpp +LOCAL_MODULE := ss-tunnel +LOCAL_SRC_FILES := $(addprefix shadowsocks/src/, $(SHADOWSOCKS_SOURCES)) LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DUDPRELAY_LOCAL -DUDPRELAY_TUNNEL \ -DUSE_CRYPTO_OPENSSL -DANDROID -DHAVE_CONFIG_H -DSSTUNNEL_JNI \ -I$(LOCAL_PATH)/libev/ \ @@ -188,7 +184,7 @@ LOCAL_STATIC_LIBRARIES := libev libcrypto LOCAL_LDLIBS := -llog -include $(BUILD_SHARED_LIBRARY) +include $(BUILD_EXECUTABLE) ######################################################## ## system @@ -292,7 +288,7 @@ LOCAL_MODULE := tun2socks-jni LOCAL_LDLIBS := -ldl -llog -LOCAL_SRC_FILES := $(addprefix badvpn/, $(TUN2SOCKS_SOURCES)) main-jni.cpp +LOCAL_SRC_FILES := $(addprefix badvpn/, $(TUN2SOCKS_SOURCES)) tun2socks-jni.cpp include $(BUILD_SHARED_LIBRARY) diff --git a/src/main/jni/Application.mk b/src/main/jni/Application.mk index d3fa0156..d8820faa 100644 --- a/src/main/jni/Application.mk +++ b/src/main/jni/Application.mk @@ -1,4 +1,4 @@ -APP_ABI := armeabi-v7a arm64-v8a x86 x86_64 +APP_ABI := armeabi-v7a x86 APP_PLATFORM := android-16 APP_STL := stlport_static NDK_TOOLCHAIN_VERSION := 4.9 diff --git a/src/main/jni/badvpn/tun2socks/tun2socks.c b/src/main/jni/badvpn/tun2socks/tun2socks.c index d14310a6..9d17d04d 100644 --- a/src/main/jni/badvpn/tun2socks/tun2socks.c +++ b/src/main/jni/badvpn/tun2socks/tun2socks.c @@ -123,6 +123,28 @@ static void insert_connection (BAddr local_addr, BAddr remote_addr, uint16_t por BAVL_Insert(&connections_tree, &tmp->connections_tree_node, NULL); } } + +static void free_connections() +{ + while (!BAVL_IsEmpty(&connections_tree)) { + Connection *con = UPPER_OBJECT(BAVL_GetLast(&connections_tree), Connection, connections_tree_node); + BAVL_Remove(&connections_tree, &con->connections_tree_node); + } +} + +static void tcp_remove(struct tcp_pcb* pcb_list) +{ + struct tcp_pcb *pcb = pcb_list; + struct tcp_pcb *pcb2; + + while(pcb != NULL) + { + pcb2 = pcb; + pcb = pcb->next; + tcp_abort(pcb2); + } +} + #endif #define LOGGER_STDOUT 1 @@ -266,9 +288,11 @@ int num_clients; #ifdef ANDROID // Address of dnsgw BAddr dnsgw; +void terminate (void); +#else +static void terminate (void); #endif -static void terminate (void); static void print_help (const char *name); static void print_version (void); static int parse_arguments (int argc, char *argv[]); @@ -386,12 +410,6 @@ int main (int argc, char **argv) return 0; } -#ifdef ANDROID - if (options.pid) { - daemonize(options.pid); - } -#endif - // initialize logger switch (options.logger) { case LOGGER_STDOUT: @@ -544,6 +562,12 @@ int main (int argc, char **argv) // init number of clients num_clients = 0; + +#if 0 + if (options.pid) { + daemonize(options.pid); + } +#endif // enter event loop BLog(BLOG_NOTICE, "entering event loop"); @@ -571,6 +595,14 @@ int main (int argc, char **argv) BReactor_RemoveTimer(&ss, &tcp_timer); BFree(device_write_buf); + +#ifdef ANDROID + tcp_remove(tcp_bound_pcbs); + tcp_remove(tcp_active_pcbs); + tcp_remove(tcp_tw_pcbs); + free_connections(); +#endif + fail5: BPending_Free(&lwip_init_job); if (options.udpgw_remote_server_addr) { diff --git a/src/main/jni/tun2socks-jni.cpp b/src/main/jni/tun2socks-jni.cpp new file mode 100644 index 00000000..aac2834f --- /dev/null +++ b/src/main/jni/tun2socks-jni.cpp @@ -0,0 +1,79 @@ +#include +#include +#include + +typedef unsigned short char16_t; + +class String8 { +public: + String8() { + mString = 0; + } + + ~String8() { + if (mString) { + free(mString); + } + } + + void set(const char16_t* o, size_t numChars) { + if (mString) { + free(mString); + } + mString = (char*) malloc(numChars + 1); + if (!mString) { + return; + } + for (size_t i = 0; i < numChars; i++) { + mString[i] = (char) o[i]; + } + mString[numChars] = '\0'; + } + + const char* string() { + return mString; + } +private: + char* mString; +}; + +extern "C" { + +int main(int argc, char* args[]); +void terminate (void); + +jint Java_com_github_shadowsocks_Tun2Socks_start(JNIEnv *env, jobject thiz, jobjectArray argv) { + + int argc = argv ? env->GetArrayLength(argv) : 0; + char **args = NULL; + String8 tmp_8; + + if (argc > 0) { + args = (char **)malloc((argc+1)*sizeof(char *)); + for (int i = 0; i < argc; ++i) { + jstring arg = reinterpret_cast(env->GetObjectArrayElement(argv, i)); + const jchar *str = env->GetStringCritical(arg, 0); + tmp_8.set(str, env->GetStringLength(arg)); + env->ReleaseStringCritical(arg, str); + args[i] = strdup(tmp_8.string()); + } + args[argc] = NULL; + + pid_t pid; + pid = fork(); + if (pid == 0) { + int ret = main(argc, args); + return ret; + } + + if (args != NULL) free(args); + } + + return 0; +} + +jint Java_com_github_shadowsocks_Tun2Socks_stop(JNIEnv *env, jobject thiz) { + terminate(); +} + +} diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index ee09ca0c..012cf9ae 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -123,7 +123,7 @@ object Shadowsocks { val FEATRUE_PREFS = Array(Key.route, Key.isGlobalProxy, Key.proxyedApps, Key.isUdpDns, Key.isAutoConnect) - val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.IPTABLES) + val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.SS_TUNNEL, Executable.SS_LOCAL) // Helper functions def updateListPreference(pref: Preference, value: String) { @@ -834,6 +834,14 @@ class Shadowsocks crash_recovery() + copyAssets(System.getABI) + + val ab = new ArrayBuffer[String] + for (executable <- Shadowsocks.EXECUTABLES) { + ab.append("chmod 755 " + Path.BASE + executable) + } + Console.runCommand(ab.toArray) + } private def recovery() { diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index f85b0a39..b396ea27 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -102,14 +102,17 @@ class ShadowsocksNatService extends Service with BaseService { }) } + val conf = ConfigUtils + .SHADOWSOCKS.format(config.proxy, config.remotePort, config.localPort, + config.sitekey, config.encMethod, 10) + ConfigUtils.printToFile(new File(Path.BASE + "ss-local.json"))(p => { + p.println(conf) + }) + val cmd = new ArrayBuffer[String] - cmd += ("ss-local" + cmd += (Path.BASE + "ss-local" , "-b" , "127.0.0.1" - , "-s" , config.proxy - , "-p" , config.remotePort.toString - , "-l" , config.localPort.toString - , "-k" , config.sitekey - , "-m" , config.encMethod + , "-c" , Path.BASE + "ss-local.json" , "-f" , Path.BASE + "ss-local.pid") if (config.route != Route.ALL) { @@ -118,49 +121,59 @@ class ShadowsocksNatService extends Service with BaseService { } if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) - - Core.sslocal(cmd.toArray) + Console.runCommand(cmd.mkString(" ")) } - def startDnsDaemon() { + def startTunnel() { if (config.isUdpDns) { + val conf = ConfigUtils + .SHADOWSOCKS.format(config.proxy, config.remotePort, 8153, + config.sitekey, config.encMethod, 10) + ConfigUtils.printToFile(new File(Path.BASE + "ss-tunnel.json"))(p => { + p.println(conf) + }) val cmd = new ArrayBuffer[String] - cmd += ("ss-tunnel" , "-u" + cmd += (Path.BASE + "ss-tunnel" , "-u" , "-b" , "127.0.0.1" , "-l" , "8153" , "-L" , "8.8.8.8:53" - , "-s" , config.proxy - , "-p" , config.remotePort.toString - , "-k" , config.sitekey - , "-m" , config.encMethod + , "-c" , Path.BASE + "ss-tunnel.json" , "-f" , Path.BASE + "ss-tunnel.pid") - if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) - Core.sstunnel(cmd.toArray) - } else { - val cmdBuf = new ArrayBuffer[String] - cmdBuf += ("ss-tunnel" - , "-b", "127.0.0.1" - , "-l", "8163" - , "-L", "8.8.8.8:53" - , "-s", config.proxy - , "-p", config.remotePort.toString - , "-k", config.sitekey - , "-m", config.encMethod - , "-f", Path.BASE + "ss-tunnel.pid") - if (BuildConfig.DEBUG) Log.d(TAG, cmdBuf.mkString(" ")) - Core.sstunnel(cmdBuf.toArray) + if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) + Console.runCommand(cmd.mkString(" ")) + } else { val conf = ConfigUtils - .PDNSD_BYPASS.format("127.0.0.1", getString(R.string.exclude), 8163) - ConfigUtils.printToFile(new File(Path.BASE + "pdnsd.conf"))(p => { - p.println(conf) + .SHADOWSOCKS.format(config.proxy, config.remotePort, 8163, + config.sitekey, config.encMethod, 10) + ConfigUtils.printToFile(new File(Path.BASE + "ss-tunnel.json"))(p => { + p.println(conf) }) - val cmd = Path.BASE + "pdnsd -c " + Path.BASE + "pdnsd.conf" - if (BuildConfig.DEBUG) Log.d(TAG, cmd) - Core.pdnsd(cmd.split(" ")) + val cmdBuf = new ArrayBuffer[String] + cmdBuf += (Path.BASE + "ss-tunnel" + , "-b" , "127.0.0.1" + , "-l" , "8163" + , "-L" , "8.8.8.8:53" + , "-c" , Path.BASE + "ss-tunnel.json" + , "-f" , Path.BASE + "ss-tunnel.pid") + + if (BuildConfig.DEBUG) Log.d(TAG, cmdBuf.mkString(" ")) + Console.runCommand(cmdBuf.mkString(" ")) } } + def startDnsDaemon() { + val conf = ConfigUtils + .PDNSD_BYPASS.format("127.0.0.1", getString(R.string.exclude), 8163) + ConfigUtils.printToFile(new File(Path.BASE + "pdnsd.conf"))(p => { + p.println(conf) + }) + val cmd = Path.BASE + "pdnsd -c " + Path.BASE + "pdnsd.conf" + + if (BuildConfig.DEBUG) Log.d(TAG, cmd) + Console.runCommand(cmd) + } + def getVersionName: String = { var version: String = null try { @@ -175,20 +188,21 @@ class ShadowsocksNatService extends Service with BaseService { def startRedsocksDaemon() { val conf = ConfigUtils.REDSOCKS.format(config.localPort) - val cmd = "redsocks -p %sredsocks.pid -c %sredsocks.conf" + val cmd = Path.BASE + "redsocks -p %sredsocks.pid -c %sredsocks.conf" .format(Path.BASE, Path.BASE) ConfigUtils.printToFile(new File(Path.BASE + "redsocks.conf"))(p => { p.println(conf) }) - if (BuildConfig.DEBUG) Log.d(TAG, cmd) - Core.redsocks(cmd.split(" ")) + if (BuildConfig.DEBUG) Log.d(TAG, cmd) + Console.runCommand(cmd); } /** Called when the activity is first created. */ def handleConnection: Boolean = { - startDnsDaemon() + startTunnel() + if (!config.isUdpDns) startDnsDaemon() startRedsocksDaemon() startShadowsocksDaemon() setupIptables() @@ -266,22 +280,16 @@ class ShadowsocksNatService extends Service with BaseService { } def killProcesses() { + for (task <- Array("ss-local", "ss-tunnel", "pdnsd", "redsocks")) { + try { + val pid = scala.io.Source.fromFile(Path.BASE + task + ".pid").mkString.trim.toInt + Process.killProcess(pid) + Log.d(TAG, "kill pid: " + pid) + } catch { + case e: Throwable => Log.e(TAG, "unable to kill " + task, e) + } + } Console.runRootCommand(Utils.getIptables + " -t nat -F OUTPUT") - - val ab = new ArrayBuffer[String] - - ab.append("kill -9 `cat " + Path.BASE + "ss-tunnel.pid`") - ab.append("kill -9 `cat " + Path.BASE +"redsocks.pid`") - ab.append("killall -9 redsocks") - ab.append("kill -15 `cat " + Path.BASE + "pdnsd.pid`") - ab.append("killall -15 pdnsd") - - Console.runRootCommand(ab.toArray) - - ab.clear() - ab.append("kill -9 `cat " + Path.BASE + "ss-local.pid`") - - Console.runCommand(ab.toArray) } def flushDNS() { diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index 692bb071..12c04a89 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -107,14 +107,17 @@ class ShadowsocksVpnService extends VpnService with BaseService { }) } + val conf = ConfigUtils + .SHADOWSOCKS.format(config.proxy, config.remotePort, config.localPort, + config.sitekey, config.encMethod, 10) + ConfigUtils.printToFile(new File(Path.BASE + "ss-local.json"))(p => { + p.println(conf) + }) + val cmd = new ArrayBuffer[String] - cmd +=("ss-local", "-u" + cmd +=(Path.BASE + "ss-local", "-u" , "-b", "127.0.0.1" - , "-s", config.proxy - , "-p", config.remotePort.toString - , "-l", config.localPort.toString - , "-k", config.sitekey - , "-m", config.encMethod + , "-c", Path.BASE + "ss-local.json" , "-f", Path.BASE + "ss-local.pid") if (Utils.isLollipopOrAbove && config.route != Route.ALL) { @@ -123,22 +126,26 @@ class ShadowsocksVpnService extends VpnService with BaseService { } if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) - Core.sslocal(cmd.toArray) + Console.runCommand(cmd.mkString(" ")) } def startDnsTunnel() = { + val conf = ConfigUtils + .SHADOWSOCKS.format(config.proxy, config.remotePort, 8163, + config.sitekey, config.encMethod, 10) + ConfigUtils.printToFile(new File(Path.BASE + "ss-tunnel.json"))(p => { + p.println(conf) + }) val cmd = new ArrayBuffer[String] - cmd +=("ss-tunnel" + cmd +=(Path.BASE + "ss-tunnel" , "-b", "127.0.0.1" , "-l", "8163" , "-L", "8.8.8.8:53" - , "-s", config.proxy - , "-p", config.remotePort.toString - , "-k", config.sitekey - , "-m", config.encMethod + , "-c", Path.BASE + "ss-tunnel.json" , "-f", Path.BASE + "ss-tunnel.pid") + if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) - Core.sstunnel(cmd.toArray) + Console.runCommand(cmd.mkString(" ")) } def startDnsDaemon() { @@ -153,8 +160,9 @@ class ShadowsocksVpnService extends VpnService with BaseService { p.println(conf) }) val cmd = Path.BASE + "pdnsd -c " + Path.BASE + "pdnsd.conf" + if (BuildConfig.DEBUG) Log.d(TAG, cmd) - Core.pdnsd(cmd.split(" ")) + Console.runCommand(cmd) } def getVersionName: String = { @@ -314,7 +322,9 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (BuildConfig.DEBUG) Log.d(TAG, cmd) - Core.tun2socks(cmd.split(" ")) + spawn { + Tun2Socks.start(cmd.split(" ")) + } } /** Called when the activity is first created. */ @@ -352,7 +362,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { } def killProcesses() { - for (task <- Array("ss-local", "ss-tunnel", "tun2socks", "pdnsd")) { + for (task <- Array("ss-local", "ss-tunnel", "pdnsd")) { try { val pid = scala.io.Source.fromFile(Path.BASE + task + ".pid").mkString.trim.toInt Process.killProcess(pid) @@ -361,6 +371,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { case e: Throwable => Log.e(TAG, "unable to kill " + task, e) } } + Tun2Socks.stop(); } override def startRunner(c: Config) { diff --git a/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala b/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala index 0ee5d488..80e2c34a 100644 --- a/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala +++ b/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala @@ -46,7 +46,7 @@ import scalaj.http.{HttpOptions, Http} import com.github.shadowsocks.aidl.Config object ConfigUtils { - val SHADOWSOCKS = "{\"server\": [%s], \"server_port\": %d, \"local_port\": %d, \"password\": %s, \"timeout\": %d}" + val SHADOWSOCKS = "{\"server\": \"%s\", \"server_port\": %d, \"local_port\": %d, \"password\": \"%s\", \"method\":\"%s\", \"timeout\": %d}" val REDSOCKS = "base {" + " log_debug = off;" + " log_info = off;" +