├── .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 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
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 | 
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 |
27 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/raw/lightsocks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/app/src/main/res/raw/lightsocks
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | LightSocks
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/liyiheng/lightsocks/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.liyiheng.lightsocks;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Oct 13 14:31:36 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/lightsocks-rs/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | **/*.rs.bk
3 | Cargo.lock
4 |
--------------------------------------------------------------------------------
/lightsocks-rs/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "lightsocks-rs"
3 | version = "0.1.0"
4 | authors = ["liyiheng "]
5 | edition = "2018"
6 |
7 | [dependencies]
8 | base64 = "0.10.0"
9 | rand = "0.6"
10 | tokio = "0.1"
11 |
--------------------------------------------------------------------------------
/lightsocks-rs/src/bin/local.rs:
--------------------------------------------------------------------------------
1 | use tokio::{io, net::TcpStream, prelude::*};
2 | fn main() {
3 | let addr = "127.0.0.1:4321".parse().unwrap();
4 | //tokio::net::TcpListener::bind(&addr);
5 | let hello = TcpStream::connect(&addr)
6 | .and_then(|stream| {
7 | println!("connected");
8 | io::write_all(stream, "hello world\n").then(|result| {
9 | println!("wrote to stream; success={:?}", result.is_ok());
10 | Ok(())
11 | })
12 | })
13 | .map_err(|err| {
14 | println!("failed to connect:{}", err);
15 | });
16 | tokio::run(hello);
17 | }
18 |
--------------------------------------------------------------------------------
/lightsocks-rs/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![allow(dead_code)]
2 | use base64;
3 | use rand::prelude::*;
4 |
5 | pub struct Password(pub [u8; 256]);
6 |
7 | impl std::string::ToString for Password {
8 | fn to_string(&self) -> String {
9 | base64::encode(&self.0[..])
10 | }
11 | }
12 |
13 | impl From for Password {
14 | fn from(s: String) -> Password {
15 | let mut arr = [0u8; 256];
16 | let dat: Vec = base64::decode(&s).unwrap_or_default();
17 | for (&x, p) in dat.iter().zip(arr.iter_mut()) {
18 | *p = x;
19 | }
20 | Password(arr)
21 | }
22 | }
23 |
24 | impl From<[u8; 256]> for Password {
25 | fn from(dat: [u8; 256]) -> Password {
26 | Password(dat)
27 | }
28 | }
29 |
30 | impl Password {
31 | pub fn new() -> Password {
32 | let mut arr = [0u8; 256];
33 | for i in 0..256 {
34 | arr[i] = i as u8;
35 | }
36 | arr[..].shuffle(&mut rand::thread_rng());
37 | Password(arr)
38 | }
39 |
40 | pub fn valid(&self) -> bool {
41 | let mut table = [0u8; 256];
42 | for i in self.0.iter() {
43 | table[*i as usize] = *i;
44 | }
45 | for (i, v) in table.iter().enumerate() {
46 | if i as u8 != *v {
47 | return false;
48 | }
49 | }
50 | true
51 | }
52 | }
53 |
54 | #[test]
55 | fn password() {
56 | let p = Password::new();
57 | let mut set = std::collections::HashSet::new();
58 | for b in p.0.iter() {
59 | if set.contains(b) {
60 | panic!("{}", b);
61 | } else {
62 | set.insert(b);
63 | }
64 | }
65 | let s = p.to_string();
66 | let passwd = Password::from(s);
67 | assert_eq!(true, passwd.valid());
68 | for (&a, &b) in passwd.0.iter().zip(p.0.iter()) {
69 | assert_eq!(a, b);
70 | }
71 | }
72 |
73 | pub struct Cipher {
74 | encoder: Password,
75 | decoder: Password,
76 | }
77 |
78 | impl Cipher {
79 | pub fn new(encoder: Password) -> Cipher {
80 | let mut decoder = Password([0u8; 256]);
81 | for (i, &v) in encoder.0.iter().enumerate() {
82 | decoder.0[v as usize] = i as u8;
83 | }
84 | Cipher {
85 | encoder: encoder,
86 | decoder: decoder,
87 | }
88 | }
89 | pub fn encode(&self, dat: &mut Vec) {
90 | for v in dat {
91 | *v = self.encoder.0[*v as usize];
92 | }
93 | }
94 | pub fn decode(&self, dat: &mut Vec) {
95 | for v in dat {
96 | *v = self.decoder.0[*v as usize];
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/lightsocks/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | bin
3 | .DS_Store
4 | config.json
5 | dist/
6 |
--------------------------------------------------------------------------------
/lightsocks/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 |
3 | go:
4 | - 1.9
5 |
6 | script: go test -bench=. -run=. ./...
--------------------------------------------------------------------------------
/lightsocks/cmd/config.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "encoding/json"
7 | "log"
8 | "path"
9 | "io/ioutil"
10 | "github.com/mitchellh/go-homedir"
11 | )
12 |
13 | const (
14 | ConfigFileName = ".lightsocks.json"
15 | )
16 |
17 | type Config struct {
18 | ListenAddr string `json:"listen"`
19 | RemoteAddr string `json:"remote"`
20 | Password string `json:"password"`
21 | }
22 |
23 | // 配置文件路径
24 | var configPath string
25 |
26 | func init() {
27 | home, _ := homedir.Dir()
28 | configPath = path.Join(home, ConfigFileName)
29 | }
30 |
31 | // 保存配置到配置文件
32 | func (config *Config) SaveConfig() {
33 | configJson, _ := json.MarshalIndent(config, "", " ")
34 | err := ioutil.WriteFile(configPath, configJson, 0644)
35 | if err != nil {
36 | fmt.Errorf("保存配置到文件 %s 出错: %s", configPath, err)
37 | }
38 | log.Printf("保存配置到文件 %s 成功\n", configPath)
39 | }
40 |
41 | func (config *Config) ReadConfig() {
42 | // 如果配置文件存在,就读取配置文件中的配置 assign 到 config
43 | if _, err := os.Stat(configPath); !os.IsNotExist(err) {
44 | log.Printf("从文件 %s 中读取配置\n", configPath)
45 | file, err := os.Open(configPath)
46 | if err != nil {
47 | log.Fatalf("打开配置文件 %s 出错:%s", configPath, err)
48 | }
49 | defer file.Close()
50 |
51 | err = json.NewDecoder(file).Decode(config)
52 | if err != nil {
53 | log.Fatalf("格式不合法的 JSON 配置文件:\n%s", file)
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lightsocks/cmd/config_test.go:
--------------------------------------------------------------------------------
1 | package cmd
2 | //
3 | //import (
4 | // "testing"
5 | // "os"
6 | //)
7 | //
8 | //func TestReadConfig(t *testing.T) {
9 | // config := ReadConfig()
10 | // if config.Password == "" {
11 | // t.Error("返回的密码不能为空")
12 | // }
13 | // if config.ListenAddr == "" {
14 | // t.Error("返回的 ListenAddr 不能为空")
15 | // }
16 | // if config.RemoteAddr == "" {
17 | // t.Error("返回的 RemoteAddr 不能为空")
18 | // }
19 | // if _, err := os.Stat(configPath); os.IsNotExist(err) {
20 | // t.Error("配置文件没有生成")
21 | // }
22 | //}
23 |
--------------------------------------------------------------------------------
/lightsocks/cmd/e2e_test.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "io"
5 | "log"
6 | "math/rand"
7 | "net"
8 | "reflect"
9 | "testing"
10 |
11 | "../core"
12 | "../local"
13 | "../server"
14 | "golang.org/x/net/proxy"
15 | )
16 |
17 | const (
18 | MaxPackSize = 1024 * 1024 * 2 // 2Mb
19 | EchoServerAddr = "127.0.0.1:3453"
20 | LightSocksProxyLocalAddr = "127.0.0.1:7441"
21 | LightSocksProxyServerAddr = "127.0.0.1:7442"
22 | )
23 |
24 | var (
25 | lightsocksDialer proxy.Dialer
26 | )
27 |
28 | func init() {
29 | go runEchoServer()
30 | go runLightsocksProxyServer()
31 | // 初始化代理socksDialer
32 | var err error
33 | lightsocksDialer, err = proxy.SOCKS5("tcp", LightSocksProxyLocalAddr, nil, proxy.Direct)
34 | if err != nil {
35 | log.Fatalln(err)
36 | }
37 | }
38 |
39 | // 启动echo server
40 | func runEchoServer() {
41 | listener, err := net.Listen("tcp", EchoServerAddr)
42 | if err != nil {
43 | log.Fatalln(err)
44 | }
45 | defer listener.Close()
46 | for {
47 | conn, err := listener.Accept()
48 | if err != nil {
49 | log.Fatalln("listener.Accept", err)
50 | continue
51 | }
52 | log.Println("EchoServer", "listener.Accept")
53 | go func() {
54 | defer conn.Close()
55 | io.Copy(conn, conn)
56 | log.Println("EchoServer", "conn.Close")
57 | }()
58 | }
59 | }
60 |
61 | func runLightsocksProxyServer() {
62 | password := core.RandPassword()
63 | localAddr, _ := net.ResolveTCPAddr("tcp", LightSocksProxyLocalAddr)
64 | serverAddr, _ := net.ResolveTCPAddr("tcp", LightSocksProxyServerAddr)
65 | serverS := local.New(password, localAddr, serverAddr)
66 | localS := server.New(password, serverAddr)
67 | go serverS.Listen()
68 | localS.Listen()
69 | }
70 |
71 | // 发生一次连接测试经过代理后的数据传输的正确性
72 | // packSize 代表这个连接发生数据的大小
73 | func testConnect(packSize int) {
74 | // 随机生产 MaxPackSize byte的[]byte
75 | data := make([]byte, packSize)
76 | _, err := rand.Read(data)
77 | buf := make([]byte, len(data))
78 | conn, err := lightsocksDialer.Dial("tcp", EchoServerAddr)
79 | if err != nil {
80 | log.Fatalln(err)
81 | }
82 | go func() {
83 | conn.Write(data)
84 | }()
85 | _, err = io.ReadFull(conn, buf)
86 | conn.Close()
87 | if err != nil {
88 | log.Fatalln("io.ReadFull", err)
89 | }
90 | if !reflect.DeepEqual(data, buf) {
91 | log.Fatalln("通过 Lightsocks 代理传输得到的数据前后不一致")
92 | }
93 | }
94 |
95 | // 获取 发送 data 到 echo server 并且收到全部返回 所花费到时间
96 | func BenchmarkLightsocks(b *testing.B) {
97 | for i := 0; i < b.N; i++ {
98 | b.StartTimer()
99 | testConnect(rand.Intn(MaxPackSize))
100 | b.StopTimer()
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/lightsocks/cmd/lightsocks-local/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net"
7 |
8 | "flag"
9 |
10 | "../../cmd"
11 | "../../core"
12 | "../../local"
13 | )
14 |
15 | const (
16 | DefaultListenAddr = ":7448"
17 | )
18 |
19 | var version = "master"
20 |
21 | func main() {
22 | log.SetFlags(log.Lshortfile)
23 |
24 | passwd := flag.String("password", "", "")
25 | rmt := flag.String("remote", "", "")
26 | listen := flag.String("listen", DefaultListenAddr, "")
27 | flag.Parse()
28 |
29 | if *rmt == "" || *passwd == "" {
30 | config := &cmd.Config{
31 | ListenAddr: DefaultListenAddr,
32 | }
33 | config.ReadConfig()
34 | config.SaveConfig()
35 |
36 | *rmt = config.RemoteAddr
37 | *passwd = config.Password
38 | *listen = config.ListenAddr
39 | }
40 |
41 | password, err := core.ParsePassword(*passwd)
42 | if err != nil {
43 | log.Fatalln(err)
44 | }
45 | listenAddr, err := net.ResolveTCPAddr("tcp", *listen)
46 | if err != nil {
47 | log.Fatalln(err)
48 | }
49 | remoteAddr, err := net.ResolveTCPAddr("tcp", *rmt)
50 | if err != nil {
51 | log.Fatalln(err)
52 | }
53 |
54 | // 启动 local 端并监听
55 | lsLocal := local.New(password, listenAddr, remoteAddr)
56 | lsLocal.AfterListen = func(listenAddr net.Addr) {
57 | log.Printf("lightsocks-local:%s 启动成功 监听在 %s\n", version, listenAddr.String())
58 | log.Println("使用配置:", fmt.Sprintf(`
59 | 本地监听地址 listen:
60 | %s
61 | 远程服务地址 remote:
62 | %s
63 | 密码 password:
64 | %s
65 | `, listenAddr, remoteAddr, password))
66 | }
67 | log.Fatalln(lsLocal.Listen())
68 | }
69 |
--------------------------------------------------------------------------------
/lightsocks/cmd/lightsocks-server/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net"
6 | "fmt"
7 | "../../server"
8 | "../../cmd"
9 | "../../core"
10 | "github.com/phayes/freeport"
11 | )
12 |
13 | var version = "master"
14 |
15 | func main() {
16 | log.SetFlags(log.Lshortfile)
17 |
18 | var err error
19 |
20 | // 服务端监听端口随机生成
21 | port, err := freeport.GetFreePort()
22 | if err != nil {
23 | // 随机端口失败就采用 7448
24 | port = 7448
25 | }
26 | config := &cmd.Config{
27 | ListenAddr: fmt.Sprintf(":%d", port),
28 | // 密码随机生成
29 | Password: core.RandPassword().String(),
30 | }
31 | config.ReadConfig()
32 | config.SaveConfig()
33 |
34 | password, err := core.ParsePassword(config.Password)
35 | if err != nil {
36 | log.Fatalln(err)
37 | }
38 | listenAddr, err := net.ResolveTCPAddr("tcp", config.ListenAddr)
39 | if err != nil {
40 | log.Fatalln(err)
41 | }
42 |
43 | // 启动 server 端并监听
44 | lsServer := server.New(password, listenAddr)
45 | lsServer.AfterListen = func(listenAddr net.Addr) {
46 | log.Printf("lightsocks-server:%s 启动成功 监听在 %s\n", version, listenAddr.String())
47 | log.Println("使用配置:", fmt.Sprintf(`
48 | 本地监听地址 listen:
49 | %s
50 | 密码 password:
51 | %s
52 | `, listenAddr, password))
53 | }
54 | log.Fatalln(lsServer.Listen())
55 | }
56 |
--------------------------------------------------------------------------------
/lightsocks/core/cipher.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | type Cipher struct {
4 | // 编码用的密码
5 | encodePassword *Password
6 | // 解码用的密码
7 | decodePassword *Password
8 | }
9 |
10 | // 编码原数据
11 | func (cipher *Cipher) encode(bs []byte) {
12 | for i, v := range bs {
13 | bs[i] = cipher.encodePassword[v]
14 | }
15 | }
16 |
17 | // 解码加密后的数据到原数据
18 | func (cipher *Cipher) decode(bs []byte) {
19 | for i, v := range bs {
20 | bs[i] = cipher.decodePassword[v]
21 | }
22 | }
23 |
24 | // 新建一个编码解码器
25 | func NewCipher(encodePassword *Password) *Cipher {
26 | decodePassword := &Password{}
27 | for i, v := range encodePassword {
28 | encodePassword[i] = v
29 | decodePassword[v] = byte(i)
30 | }
31 | return &Cipher{
32 | encodePassword: encodePassword,
33 | decodePassword: decodePassword,
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lightsocks/core/cipher_test.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "testing"
5 | "reflect"
6 | "crypto/rand"
7 | )
8 |
9 | const (
10 | MB = 1024 * 1024
11 | )
12 |
13 | // 测试 Cipher 加密解密
14 | func TestCipher(t *testing.T) {
15 | password := RandPassword()
16 | t.Log(password)
17 | cipher := NewCipher(password)
18 | // 原数据
19 | org := make([]byte, PasswordLength)
20 | for i := 0; i < PasswordLength; i++ {
21 | org[i] = byte(i)
22 | }
23 | // 复制一份原数据到 tmp
24 | tmp := make([]byte, PasswordLength)
25 | copy(tmp, org)
26 | t.Log(tmp)
27 | // 加密 tmp
28 | cipher.encode(tmp)
29 | t.Log(tmp)
30 | // 解密 tmp
31 | cipher.decode(tmp)
32 | t.Log(tmp)
33 | if !reflect.DeepEqual(org, tmp) {
34 | t.Error("解码编码数据后无法还原数据,数据不对应")
35 | }
36 | }
37 |
38 | func BenchmarkEncode(b *testing.B) {
39 | password := RandPassword()
40 | cipher := NewCipher(password)
41 | bs := make([]byte, MB)
42 | b.ResetTimer()
43 | rand.Read(bs)
44 | cipher.encode(bs)
45 | }
46 |
47 | func BenchmarkDecode(b *testing.B) {
48 | password := RandPassword()
49 | cipher := NewCipher(password)
50 | bs := make([]byte, MB)
51 | b.ResetTimer()
52 | rand.Read(bs)
53 | cipher.decode(bs)
54 | }
55 |
--------------------------------------------------------------------------------
/lightsocks/core/password.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "math/rand"
5 | "errors"
6 | "strings"
7 | "time"
8 | "encoding/base64"
9 | )
10 |
11 | const PasswordLength = 256
12 |
13 | var ErrInvalidPassword = errors.New("不合法的密码")
14 |
15 | type Password [PasswordLength]byte
16 |
17 | func init() {
18 | rand.Seed(time.Now().Unix())
19 | }
20 |
21 | // 采用base64编码把密码转换为字符串
22 | func (password *Password) String() string {
23 | return base64.StdEncoding.EncodeToString(password[:])
24 | }
25 |
26 | // 解析采用base64编码的字符串获取密码
27 | func ParsePassword(passwordString string) (*Password, error) {
28 | bs, err := base64.StdEncoding.DecodeString(strings.TrimSpace(passwordString))
29 | if err != nil || len(bs) != PasswordLength {
30 | return nil, ErrInvalidPassword
31 | }
32 | password := Password{}
33 | copy(password[:], bs)
34 | bs = nil
35 | return &password, nil
36 | }
37 |
38 | // 产生 256个byte随机组合的 密码,最后会使用base64编码为字符串存储在配置文件中
39 | // 不能出现任何一个重复的byte位,必须又 0-255 组成,并且都需要包含
40 | func RandPassword() *Password {
41 | intArr := rand.Perm(PasswordLength)
42 | password := &Password{}
43 | sameCount := 0
44 | for i, v := range intArr {
45 | password[i] = byte(v)
46 | if i == v {
47 | sameCount++
48 | }
49 | }
50 | // 不会出现如何一个byte位出现重复
51 | if sameCount > 0 {
52 | password = nil
53 | return RandPassword()
54 | } else {
55 | return password
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/lightsocks/core/password_test.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "testing"
5 | "sort"
6 | "reflect"
7 | )
8 |
9 | func (password *Password) Len() int {
10 | return PasswordLength
11 | }
12 |
13 | func (password *Password) Less(i, j int) bool {
14 | return password[i] < password[j]
15 | }
16 |
17 | func (password *Password) Swap(i, j int) {
18 | password[i], password[j] = password[j], password[i]
19 | }
20 |
21 | func TestRandPassword(t *testing.T) {
22 | password := RandPassword()
23 | t.Log(password)
24 | sort.Sort(password)
25 | for i := 0; i < PasswordLength; i++ {
26 | if password[i] != byte(i) {
27 | t.Error("不能出现任何一个重复的byte位,必须又 0-255 组成,并且都需要包含")
28 | }
29 | }
30 | }
31 |
32 | func TestPasswordString(t *testing.T) {
33 | password := RandPassword()
34 | passwordStr := password.String()
35 | decodePassword, err := ParsePassword(passwordStr)
36 | if err != nil {
37 | t.Error(err)
38 | } else {
39 | if !reflect.DeepEqual(password, decodePassword) {
40 | t.Error("密码转化成字符串后反解后数据不对应")
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lightsocks/core/securesocket.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "net"
5 | "errors"
6 | "fmt"
7 | "io"
8 | "time"
9 | )
10 |
11 | const (
12 | BufSize = 1024
13 | TIMEOUT = 10 * time.Second
14 | )
15 |
16 | // 加密传输的 TCP Socket
17 | type SecureSocket struct {
18 | Cipher *Cipher
19 | ListenAddr *net.TCPAddr
20 | RemoteAddr *net.TCPAddr
21 | }
22 |
23 | // 从输入流里读取加密过的数据,解密后把原数据放到bs里
24 | func (secureSocket *SecureSocket) DecodeRead(conn *net.TCPConn, bs []byte) (n int, err error) {
25 | n, err = conn.Read(bs)
26 | if err != nil {
27 | return
28 | }
29 | secureSocket.Cipher.decode(bs[:n])
30 | return
31 | }
32 |
33 | // 把放在bs里的数据加密后立即全部写入输出流
34 | func (secureSocket *SecureSocket) EncodeWrite(conn *net.TCPConn, bs []byte) (int, error) {
35 | secureSocket.Cipher.encode(bs)
36 | return conn.Write(bs)
37 | }
38 |
39 | // 从src中源源不断的读取原数据加密后写入到dst,直到src中没有数据可以再读取
40 | func (secureSocket *SecureSocket) EncodeCopy(dst *net.TCPConn, src *net.TCPConn) error {
41 | buf := make([]byte, BufSize)
42 | for {
43 | nr, er := src.Read(buf)
44 | if nr > 0 {
45 | nw, ew := secureSocket.EncodeWrite(dst, buf[0:nr])
46 | if ew != nil {
47 | return ew
48 | }
49 | if nr != nw {
50 | return io.ErrShortWrite
51 | }
52 | }
53 | if er != nil {
54 | if er != io.EOF {
55 | return er
56 | } else {
57 | return nil
58 | }
59 | }
60 | }
61 | }
62 |
63 | // 从src中源源不断的读取加密后的数据解密后写入到dst,直到src中没有数据可以再读取
64 | func (secureSocket *SecureSocket) DecodeCopy(dst *net.TCPConn, src *net.TCPConn) error {
65 | buf := make([]byte, BufSize)
66 | for {
67 | nr, er := secureSocket.DecodeRead(src, buf)
68 | if nr > 0 {
69 | nw, ew := dst.Write(buf[0:nr])
70 | if ew != nil {
71 | return ew
72 | }
73 | if nr != nw {
74 | return io.ErrShortWrite
75 | }
76 | }
77 | if er != nil {
78 | if er != io.EOF {
79 | return er
80 | } else {
81 | return nil
82 | }
83 | }
84 | }
85 | }
86 |
87 | // 和远程的socket建立连接,他们直接的数据传输会加密
88 | func (secureSocket *SecureSocket) DialServer() (*net.TCPConn, error) {
89 | remoteConn, err := net.DialTCP("tcp", nil, secureSocket.RemoteAddr)
90 | if err != nil {
91 | return nil, errors.New(fmt.Sprintf("连接到远程服务器 %s 失败:%s", secureSocket.RemoteAddr, err))
92 | }
93 | return remoteConn, nil
94 | }
95 |
--------------------------------------------------------------------------------
/lightsocks/goreleaser.yml:
--------------------------------------------------------------------------------
1 | builds:
2 | - binary: lightsocks-local
3 | main: ./cmd/lightsocks-local/main.go
4 | goos:
5 | - windows
6 | - darwin
7 | - linux
8 | - freebsd
9 | goarch:
10 | - amd64
11 | - 386
12 | - arm
13 | - binary: lightsocks-server
14 | main: ./cmd/lightsocks-server/main.go
15 | goos:
16 | - windows
17 | - darwin
18 | - linux
19 | - freebsd
20 | goarch:
21 | - amd64
22 | - 386
23 | - arm
--------------------------------------------------------------------------------
/lightsocks/local/local.go:
--------------------------------------------------------------------------------
1 | package local
2 |
3 | import (
4 | "net"
5 | "log"
6 | "time"
7 | "../core"
8 | )
9 |
10 | type LsLocal struct {
11 | *core.SecureSocket
12 | AfterListen func(listenAddr net.Addr)
13 | }
14 |
15 | // 新建一个本地端
16 | // 本地端的职责是:
17 | // 0.监听来自本地浏览器的代理请求
18 | // 1.转发前加密数据
19 | // 2.转发socket数据到服务端
20 | // 3.把服务端返回的数据转发给用户的浏览器
21 | func New(password *core.Password, listenAddr, remoteAddr *net.TCPAddr) *LsLocal {
22 | return &LsLocal{
23 | SecureSocket: &core.SecureSocket{
24 | Cipher: core.NewCipher(password),
25 | ListenAddr: listenAddr,
26 | RemoteAddr: remoteAddr,
27 | },
28 | }
29 | }
30 |
31 | // 本地端启动监听给用户的浏览器调用
32 | func (local *LsLocal) Listen() error {
33 | listener, err := net.ListenTCP("tcp", local.ListenAddr)
34 | if err != nil {
35 | return err
36 | }
37 |
38 | defer listener.Close()
39 |
40 | if local.AfterListen != nil {
41 | local.AfterListen(listener.Addr())
42 | }
43 |
44 | for {
45 | userConn, err := listener.AcceptTCP()
46 | if err != nil {
47 | continue
48 | }
49 | // userConn被关闭时直接清除所有数据 不管没有发送的数据
50 | userConn.SetLinger(0)
51 | go local.handleConn(userConn)
52 | }
53 | return nil
54 | }
55 |
56 | func (local *LsLocal) handleConn(userConn *net.TCPConn) {
57 | defer userConn.Close()
58 | server, err := local.DialServer()
59 | if err != nil {
60 | log.Println(err)
61 | return
62 | }
63 | defer server.Close()
64 | server.SetLinger(0)
65 | server.SetDeadline(time.Now().Add(core.TIMEOUT))
66 | // 进行转发
67 | go local.EncodeCopy(server, userConn)
68 | local.DecodeCopy(userConn, server)
69 | }
70 |
--------------------------------------------------------------------------------
/lightsocks/readme.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/gwuhaolin/lightsocks)
2 |
3 | # Lightsocks
4 | 一个轻量级网络混淆代理,基于 SOCKS5 协议,可用来代替 Shadowsocks。
5 |
6 | - 只专注于混淆,用最简单高效的混淆算法达到目的;
7 | - 不会放大传输流量,传输流量更少更快,占用资源更少;
8 | - 纯 Golang 编写,跨平台。
9 |
10 | ## 安装
11 | 去 [releases](https://github.com/gwuhaolin/lightsocks/releases) 页下载最新的可执行文件,注意选择正确的操作系统和位数。
12 | 解压后会看到2个可执行文件,分别是:
13 |
14 | - **lightsocks-local**:用于运行在本地电脑的客户端,用于桥接本地浏览器和远程代理服务,传输前会混淆数据;
15 | - **lightsocks-server**:用于运行在代理服务器的客户端,会还原混淆数据;
16 |
17 | ## 启动
18 | #### 启动 lightsocks-server
19 | 在墙外服务器下载好 lightsocks-server 后,执行命令:
20 | ```bash
21 | ./lightsocks-server
22 | ```
23 | 就可启动服务端,启动成功后会输出如下日志:
24 | ```
25 | 本地监听地址 listen:
26 | :54261
27 | 密码 password:
28 | ******
29 | ```
30 | 假如服务器的 IP 是 45.56.76.5,则以上日志的含义是指:
31 |
32 | - 服务监听在 `45.56.76.5:54261`,监听端口会随机生成;
33 | - 使用的密码是 `******`
34 |
35 | #### 启动 lightsocks-local
36 | 在本地电脑下载好 lightsocks-local 后,执行命令:
37 | ```bash
38 | ./lightsocks-local
39 | ```
40 | 就可启动本地代理客户端,会看到如下日志:
41 | ```bash
42 | 2017/10/11 10:03:16 保存配置到文件 /Users/username/.lightsocks.json 成功
43 | 2017/10/11 10:03:16 lightsocks-client:master 启动成功 监听在 [::]:7448
44 | ```
45 | 这表明生成了一份配置文件到 `/Users/username/.lightsocks.json`。
46 | 为了让客户端用指定的密码去连接服务器,需要给客户端传入参数,为此需要修改该配置文件为如下:
47 | ```json
48 | {
49 | "remote": "45.56.76.5:54261",
50 | "password": "******"
51 | }
52 | ```
53 | 重新启动 lightsocks-local 后,再使用监听在 `127.0.0.1:7448` 的本地 SOCK5 服务就可以正常使用了。
54 |
55 | ## 配置
56 | #### lightsocks-local 支持的选项:
57 | - **password**:用于加密数据的密码,字符串格式,在没有填时会自动生成;
58 | - **listen**:本地 SOCKS5 代理客户端的监听地址,格式为 `ip:port`,默认为 `0.0.0.0:7448`;
59 | - **remote**:墙外服务器的监听地址,格式为 `ip:port`,默认为 `0.0.0.0:*`。
60 |
61 | #### lightsocks-server 支持的选项:
62 | - **password**:用于加密数据的密码,字符串格式,在没有填时会自动生成;
63 | - **listen**:本地 SOCKS5 代理客户端的监听地址,格式为 `ip:port`,默认为 `0.0.0.0:*`。
64 |
65 | #### 注意:
66 | - lightsocks-local 和 lightsocks-server 的 password 必须一致才能正常正常使用,password 不要泄露。
67 | - password 会自动生成,不要自己生成。一般采用拷贝 lightsocks-server 生成的密码到 lightsocks-local 使用的本地配置文件中。
68 |
69 |
70 | 只能通过 JSON 文件的方式传参给 lightsocks-local 和 lightsocks-server,启动前会去 `~/.lightsocks.json` 文件中读取配置,启动后会把配置保存在 `~/.lightsocks.json` 文件中,
71 | 其格式为 JSON,内容大致如下:
72 | ```json
73 | {
74 | "remote": "45.56.76.5:7448",
75 | "password": "******"
76 | }
77 | ```
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/screenshot.jpg
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/smaller.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liyiheng/LightSocks-Android/947fa648c194f7e326c4e3eee0c92c374e7426f0/smaller.jpg
--------------------------------------------------------------------------------
/update_binary.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd lightsocks/cmd/lightsocks-local/
3 | gox -arch='arm' -os='linux'
4 | cd -
5 | mv lightsocks/cmd/lightsocks-local/lightsocks-local_linux_arm app/src/main/res/raw/lightsocks
--------------------------------------------------------------------------------