├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── liyiheng │ │ └── lightsocks │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── liyiheng │ │ │ └── lightsocks │ │ │ ├── Command.java │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── raw │ │ └── lightsocks │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── liyiheng │ └── lightsocks │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lightsocks-rs ├── .gitignore ├── Cargo.toml └── src │ ├── bin │ └── local.rs │ └── lib.rs ├── lightsocks ├── .gitignore ├── .travis.yml ├── cmd │ ├── config.go │ ├── config_test.go │ ├── e2e_test.go │ ├── lightsocks-local │ │ └── main.go │ └── lightsocks-server │ │ └── main.go ├── core │ ├── cipher.go │ ├── cipher_test.go │ ├── password.go │ ├── password_test.go │ └── securesocket.go ├── goreleaser.yml ├── local │ └── local.go └── readme.md ├── screenshot.jpg ├── settings.gradle ├── smaller.jpg └── update_binary.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## [LightSocks](https://github.com/gwuhaolin/lightsocks) on Android 3 | 4 | 未完成 5 | 6 | ### TODO 7 | - lightsocks依赖换为原版,在Java层生成/修改配置文件 8 | - Android系统代理 9 | - UI 10 | - Service 11 | 12 | ![screenshot](smaller.jpg) 13 | 14 | ### 类似项目 15 | 16 | [Xsocks for Android](https://github.com/dosgo/xSocks-android) 17 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "26.0.0" 6 | defaultConfig { 7 | applicationId "com.liyiheng.lightsocks" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.3.1' 28 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 29 | testCompile 'junit:junit:4.12' 30 | } 31 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/liyiheng/Android/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/liyiheng/lightsocks/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.liyiheng.lightsocks; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.liyiheng.lightsocks", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/liyiheng/lightsocks/Command.java: -------------------------------------------------------------------------------- 1 | package com.liyiheng.lightsocks; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.support.annotation.WorkerThread; 6 | import android.text.TextUtils; 7 | import android.util.Log; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.File; 11 | import java.io.FileOutputStream; 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.io.InputStreamReader; 15 | 16 | /** 17 | * Created by liyiheng on 17-10-13. 18 | */ 19 | public class Command { 20 | interface CommandListener { 21 | 22 | @WorkerThread 23 | void lineOut(String line); 24 | 25 | @WorkerThread 26 | void done(int exit); 27 | } 28 | 29 | private static final String FILE_NAME = "c"; 30 | private String mContent; 31 | private static final int EXCEPTION_IO = -88; 32 | private static final int EXCEPTION_INTERRUPTED = -89; 33 | 34 | public Command(String mContent) { 35 | this.mContent = mContent; 36 | } 37 | 38 | public void exec(CommandListener listener) { 39 | Process process; 40 | try { 41 | process = Runtime.getRuntime().exec(mContent); 42 | } catch (IOException e) { 43 | listener.lineOut(e.getMessage()); 44 | listener.done(EXCEPTION_IO); 45 | return; 46 | } 47 | StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), listener); 48 | StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), listener); 49 | 50 | errorGobbler.start(); 51 | outputGobbler.start(); 52 | 53 | int exitVal; 54 | try { 55 | exitVal = process.waitFor(); 56 | } catch (InterruptedException e) { 57 | listener.lineOut(e.getMessage()); 58 | listener.done(EXCEPTION_INTERRUPTED); 59 | return; 60 | } 61 | listener.done(exitVal); 62 | 63 | } 64 | 65 | @SuppressWarnings("WeakerAccess") 66 | class StreamGobbler extends Thread { 67 | InputStream is; 68 | CommandListener mListener; 69 | 70 | StreamGobbler(InputStream is, CommandListener sc) { 71 | this.is = is; 72 | this.mListener = sc; 73 | } 74 | 75 | public void run() { 76 | BufferedReader br = null; 77 | try { 78 | InputStreamReader isr = new InputStreamReader(is); 79 | br = new BufferedReader(isr); 80 | String line; 81 | while ((line = br.readLine()) != null) { 82 | if (mListener != null) { 83 | mListener.lineOut(line); 84 | } 85 | } 86 | } catch (IOException e) { 87 | mListener.lineOut(e.getMessage()); 88 | mListener.done(-99); 89 | } finally { 90 | if (br != null) { 91 | try { 92 | br.close(); 93 | } catch (IOException e) { 94 | e.printStackTrace(); 95 | } 96 | } 97 | } 98 | } 99 | } 100 | 101 | public static void run(final Context context, final int resId, final String args, final CommandListener callback) { 102 | new Thread(new Runnable() { 103 | @Override 104 | public void run() { 105 | String fileName = installBinary(context, resId); 106 | if (TextUtils.isEmpty(fileName)) { 107 | return; 108 | } 109 | if (!TextUtils.isEmpty(args)) { 110 | fileName = fileName + " " + args; 111 | } 112 | Log.e("Command", fileName); 113 | new Command(fileName).exec(callback); 114 | } 115 | }).start(); 116 | } 117 | 118 | private static String installBinary(Context ctx, int resId) { 119 | try { 120 | File f = new File(ctx.getDir("bin", Context.MODE_PRIVATE), FILE_NAME); 121 | if (!f.exists()) { 122 | PackageInfo pInfo = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0); 123 | int currentVersionCode = pInfo.versionCode; 124 | if (-1 < currentVersionCode) {// TODO: ------------------- 125 | final String absPath = f.getAbsolutePath(); 126 | final FileOutputStream out = new FileOutputStream(f); 127 | final InputStream is = ctx.getResources().openRawResource(resId); 128 | byte buf[] = new byte[1024 * 50]; 129 | int len; 130 | while ((len = is.read(buf)) > 0) { 131 | out.write(buf, 0, len); 132 | } 133 | out.close(); 134 | is.close(); 135 | int i = Runtime.getRuntime().exec("chmod " + "0755" + " " + absPath).waitFor(); 136 | Log.e("Command","chmod exit "+ i); 137 | } 138 | } 139 | return f.getCanonicalPath(); 140 | } catch (Exception e) { 141 | Log.e("Command", "installBinary failed: " + e.getLocalizedMessage()); 142 | return null; 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /app/src/main/java/com/liyiheng/lightsocks/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.liyiheng.lightsocks; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.text.TextUtils; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.widget.EditText; 9 | import android.widget.TextView; 10 | import android.widget.Toast; 11 | 12 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 13 | 14 | private EditText mPasswd; 15 | private EditText mRemote; 16 | private TextView mText; 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_main); 22 | findViewById(R.id.btn_ok).setOnClickListener(this); 23 | mPasswd = ((EditText) findViewById(R.id.editText_password)); 24 | mRemote = ((EditText) findViewById(R.id.editText_remote)); 25 | mText = ((TextView) findViewById(R.id.text)); 26 | } 27 | 28 | @Override 29 | public void onClick(View v) { 30 | String args = "-password " + mPasswd.getText().toString() + " -remote " + mRemote.getText().toString(); 31 | Command.run(this, R.raw.lightsocks, args, new Command.CommandListener() { 32 | @Override 33 | public void lineOut(final String line) { 34 | if (TextUtils.isEmpty(line)) { 35 | return; 36 | } 37 | runOnUiThread(new Runnable() { 38 | @Override 39 | public void run() { 40 | Log.e("Output", line); 41 | mText.append(line); 42 | if (line.contains("成功")) { 43 | //System.setProperty("https.proxySet", "true"); 44 | System.setProperty("http.proxySet", "true"); 45 | System.setProperty("http.proxyHost", "127.0.0.1"); 46 | System.setProperty("http.proxyPort", "7448"); 47 | //System.setProperty("https.proxyHost", "127.0.0.1"); 48 | //System.setProperty("https.proxyPort", "7448"); 49 | } 50 | } 51 | }); 52 | } 53 | 54 | @Override 55 | public void done(final int exit) { 56 | runOnUiThread(new Runnable() { 57 | @Override 58 | public void run() { 59 | Log.e("Done", exit + ""); 60 | //Toast.makeText(MainActivity.this, String.valueOf(exit), Toast.LENGTH_SHORT).show(); 61 | } 62 | }); 63 | } 64 | }); 65 | } 66 | 67 | 68 | // System.clearProperty("http.proxyHost"); 69 | // System.clearProperty("http.proxyPort"); 70 | // System.clearProperty("https.proxyHost"); 71 | // System.clearProperty("https.proxyPort"); 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 21 | 22 |