作者 钟来

初始提交

正在显示 38 个修改的文件 包含 2222 行增加0 行删除
  1 +# shadowsocks-java
  2 +
  3 +Shadowsocks-java 是一个基于SOCKS5代理的使用java开发的[shadowsocks](https://github.com/shadowsocks/shadowsocks)
  4 +代理软件。可以同时作为客户端和服务端使用目前只支持TCP协议及流加密,后续会增加UDP协议和AEAD的支持。
  5 +
  6 +
  7 +
  8 +
  9 +## Build & Install
  10 +
  11 +```bash
  12 +git clone https://github.com/zhihengjiang/shasowsocks-java
  13 +cd shadowsocks-java
  14 +mvn package
  15 +```
  16 +
  17 +## Getting Started
  18 +
  19 +创建配置文件
  20 +
  21 +```json
  22 +{
  23 + "server": "my_server_ip",
  24 + "server_port": 8388,
  25 + "local_address": "127.0.0.1",
  26 + "local_port": 1080,
  27 + "password": "mypassword",
  28 + "timeout": 300,
  29 + "method": "aes-256-cfb"
  30 +}
  31 +```
  32 +
  33 +详细的参数解释可以参考 [shadowsocks](https://github.com/shadowsocks/shadowsocks/wiki) 的文档.
  34 +
  35 +在本地使用
  36 +```bash
  37 +chmod +x ./sslocal.sh
  38 +./sslocal.sh -c config.json
  39 +
  40 +```
  41 +
  42 +在服务器端使用
  43 +```bash
  44 +chmod +x ./ssserver.sh
  45 +./ssserver.sh -c config.json
  46 +
  47 +```
  48 +
  49 +更多脚本参数请输入
  50 +```bash
  51 +./ssserver.sh -h
  52 +./sslocal.sh -h
  53 +
  54 +```
  55 +
  56 +## 支持的加密方式
  57 +
  58 +### 流加密
  59 +
  60 +* `aes-128-cfb`, `aes-192-cfb`, `aes-256-cfb`
  61 +* `aes-128-ofb`, `aes-192-ofb`, `aes-256-ofb`
  62 +* `chacha20`, `chacha20-ietf`
  63 +
  64 +## TODO
  65 +
  66 +- [ ] Documentation
  67 +- [ ] 支持UDP协议
  68 +- [ ] 支持AEAD加密
  69 +- [ ] 编写使用脚本
  1 +{
  2 + "server":"127.0.0.1",
  3 + "server_port":8000,
  4 + "local_address": "127.0.0.1",
  5 + "local_port":1080,
  6 + "password":"123456",
  7 + "timeout":300,
  8 + "method":"aes-256-cfb",
  9 + "fast_open": false,
  10 + "workers": 1
  11 +}
  1 +-----BEGIN RSA PRIVATE KEY-----
  2 +MIIEowIBAAKCAQEAv3o0t1tZLXlxzO9y06062OElqgOp9ZNZhxBg1vAjg1QBgCFg
  3 +j3iNqG5RdYHmEl/Py88bB7S1TM3RvjfKHlaetbwJK3wak6VjDoFusvcKhXyBLI+D
  4 +6ocvVFLeVEeTHU3wPUGLyejUXA849yEoAOntTYCVpwcli2rKK6ntj28W5X/47HbE
  5 +ocWrBBeDbB1NIH4ZhtCaSHb8rBo2lqzrDFQHawjoICPb7N/vKbIF0YHaAfiUypFI
  6 +hF4Ajc8quYbuXn7Hp1zJc33RgayzB3Jk3B/FQGva4Dk5+XejvmKMAuziSy0Vci+R
  7 +h+bIRcyLR4ruCdrR4zvrKd8dF4gxSrMZh/Uc8QIDAQABAoIBAF83mCtuA6S3db3h
  8 +fQqCZHchTyeCduwmAClIHcAE3sQZ7D0ZW/k8i8UsRtnWZODSQHUrYlesp1OwLhMX
  9 +jy0TCg15ml3DczvkzKOT/caFTvged+X+4CyqWQDnzKPAjAnQjh0IEUmwvJmjAEL0
  10 +e/4oVddqkADlbugrjKm18OqY5Zvt8JI8yayIkwS8VuLvT3s2+XhSZ//U3goBaiis
  11 ++RrbKSGbNsQXM2+u+bd/9lgOFPQrd/zNN2/XJaopD0L4GN9je+UlEL0SovynN79D
  12 +AfF6enPSpTYYxTa2RaonvfmLPg6ezZifATZpKTRBT6A9BLMTswqd+Gu0J5z4sd3P
  13 +oq3AZ/kCgYEA8N5tk/8uJLlhTEcq6jbcYCl1FnnJz/nnqAuj9l0JzpmwBXAhHDw/
  14 +YIAZlN1yZrSF2SycPNMtFDiAcW3/0ukTD0sX9jUqboo6BfXBsSzVGEdiS1NX75bv
  15 +SgvCa1bGK3iutQj9r0f2STfqTBMIRWgjOlkoVVvDRSIZ7Qv2IHYGwacCgYEAy4F7
  16 +AxifKc98IyKSsQEtjnMV+nc1zvYaFCyvfLTJVZvZzTeLSoPpjV7ZIzvykR5oeQjT
  17 +QDgfZPJrwtS7MDNLDFvSSDCtqGFlmhZVpqgz+YrqOehMdMqKA0GQFhriRG+zRYj4
  18 +300B7A6iQnXwW03+XbkK351m9cinYf8ZeLisD6cCgYBCwxQSQleS3EMotk0h0ATz
  19 +LmqCyUzztWvNOzS+E3mlZxnP2A2FWvmiEL+GcH7GEuFKmb/QaCQFh8eqKPgQiIO8
  20 +6G6C0qepLez5O+3s4uVJrneDM12bTfWTS4Ee6VVSNUgPa6eNDuAn2TS600emnT+u
  21 +a4nvZtjP76zJ9FfLFYu33wKBgG1IDb++5BG2usm/Uhi9MjKRuJa0l2+ZFq4IxP/p
  22 +sUhIlfAuyJzuM2fYLDBQi9TECIQeahrNSIaT66xHQnICyWVMlaJwiYCnNMFHBx2k
  23 +q6xwnZEVHqGE9hIDjhVgwGrRtOo9QK/hEYwq25Vm8fiF7Hd129HzG4wXAVONgqci
  24 +PDt3AoGBAKROcAikGLrXL/KZrnqQeJizPaV+/gUv785U20lqmhEiRfNHTsyJS4OJ
  25 +UYgL+lWdvcK9RdZLP7B/QGRjjdvkf/V//L3NZqRFKGkUgAewJBr4Wljcjvc7ndvC
  26 +3aSwiZS7V4E2fAtC7VH+d0Zr12BmRcTm3HNDgmXki5ZSDhCWPfpt
  27 +-----END RSA PRIVATE KEY-----
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <modelVersion>4.0.0</modelVersion>
  6 + <groupId>org.shadowsocks</groupId>
  7 + <artifactId>shadowsocks-java</artifactId>
  8 + <version>1.0-SNAPSHOT</version>
  9 +
  10 + <dependencies>
  11 + <dependency>
  12 + <groupId>io.netty</groupId>
  13 + <artifactId>netty-all</artifactId>
  14 + <version>4.1.7.Final</version>
  15 + </dependency>
  16 +
  17 + <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
  18 + <dependency>
  19 + <groupId>org.bouncycastle</groupId>
  20 + <artifactId>bcprov-jdk15on</artifactId>
  21 + <version>1.56</version>
  22 + </dependency>
  23 +
  24 + <dependency>
  25 + <groupId>gnu.getopt</groupId>
  26 + <artifactId>java-getopt</artifactId>
  27 + <version>1.0.13</version>
  28 + </dependency>
  29 +
  30 + <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
  31 + <dependency>
  32 + <groupId>ch.qos.logback</groupId>
  33 + <artifactId>logback-classic</artifactId>
  34 + <version>1.1.9</version>
  35 + </dependency>
  36 +
  37 + <dependency>
  38 + <groupId>junit</groupId>
  39 + <artifactId>junit</artifactId>
  40 + <version>4.12</version>
  41 + <scope>test</scope>
  42 + </dependency>
  43 + <dependency>
  44 + <groupId>com.squareup.okhttp3</groupId>
  45 + <artifactId>okhttp</artifactId>
  46 + <version>3.11.0</version>
  47 + <scope>test</scope>
  48 + </dependency>
  49 + <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
  50 + <dependency>
  51 + <groupId>org.apache.httpcomponents</groupId>
  52 + <artifactId>httpclient</artifactId>
  53 + <scope>test</scope>
  54 + <version>4.5.6</version>
  55 + </dependency>
  56 + <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
  57 + <dependency>
  58 + <groupId>com.google.code.gson</groupId>
  59 + <artifactId>gson</artifactId>
  60 + <version>2.8.5</version>
  61 + </dependency>
  62 +
  63 +
  64 + </dependencies>
  65 +
  66 + <build>
  67 + <plugins>
  68 + <plugin>
  69 + <groupId>org.apache.maven.plugins</groupId>
  70 + <artifactId>maven-surefire-plugin</artifactId>
  71 + <configuration>
  72 + <skip>true</skip>
  73 + </configuration>
  74 + </plugin>
  75 + <plugin>
  76 + <groupId>org.apache.maven.plugins</groupId>
  77 + <artifactId>maven-compiler-plugin</artifactId>
  78 + <version>2.3.2</version>
  79 + <configuration>
  80 + <skip>true</skip>
  81 + <source>1.8</source>
  82 + <target>1.8</target>
  83 + </configuration>
  84 + </plugin>
  85 + <plugin>
  86 + <groupId>org.apache.maven.plugins</groupId>
  87 + <artifactId>maven-jar-plugin</artifactId>
  88 + <configuration>
  89 + <archive>
  90 + <manifest>
  91 + <addClasspath>true</addClasspath>
  92 + <classpathPrefix>lib/</classpathPrefix><!--指定classpath的前缀-->
  93 + <mainClass>org.shadowsocks.Main</mainClass><!--指定主类的类名-->
  94 + </manifest>
  95 + </archive>
  96 + </configuration>
  97 + </plugin>
  98 + <plugin>
  99 + <groupId>org.apache.maven.plugins</groupId>
  100 + <artifactId>maven-dependency-plugin</artifactId>
  101 + <executions>
  102 + <execution>
  103 + <id>copy-dependencies</id>
  104 + <phase>prepare-package</phase>
  105 + <goals>
  106 + <goal>copy-dependencies</goal>
  107 + </goals>
  108 + <configuration>
  109 + <!--指定outputDirectory-->
  110 + <outputDirectory>${project.build.directory}/lib</outputDirectory>
  111 + <overWriteReleases>false</overWriteReleases>
  112 + <overWriteSnapshots>false</overWriteSnapshots>
  113 + <overWriteIfNewer>true</overWriteIfNewer>
  114 + </configuration>
  115 + </execution>
  116 + </executions>
  117 + </plugin>
  118 + </plugins>
  119 + </build>
  120 +</project>
  1 +package org.shadowsocks;
  2 +import org.shadowsocks.config.Config;
  3 +import org.shadowsocks.config.JsonConfig;
  4 +import org.shadowsocks.util.CommandLineParser;
  5 +import org.slf4j.Logger;
  6 +import org.slf4j.LoggerFactory;
  7 +
  8 +import java.util.Arrays;
  9 +
  10 +public class Main {
  11 + private static Logger logger = LoggerFactory.getLogger(Main.class);
  12 +
  13 + public static void main( String[] args) throws Exception{
  14 + if(null == args || args.length == 0)
  15 + {
  16 + args = new String[]{"ServerMain"};
  17 + }
  18 + String path = System.getProperty("user.dir") + "/config.json";
  19 + logger.info("配置文件地址【{}】",path);
  20 + Config config = new JsonConfig(path);
  21 + logger.info("配置文件内容【{}】",config);
  22 +
  23 + String main = args[0];
  24 +// Config config = CommandLineParser.parse(Arrays.copyOfRange(args,1,args.length));
  25 + switch (main){
  26 + case "LocalMain":
  27 + new ShadowsocksLocal(config).start();break;
  28 + case "ServerMain":
  29 + new ShadowSocksServer(config).start();break;
  30 +
  31 + default:System.out.println("please set running mode");break;
  32 + }
  33 +
  34 +
  35 + }
  36 +}
  1 +package org.shadowsocks;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  4 +import io.netty.channel.ChannelFuture;
  5 +import io.netty.channel.ChannelInitializer;
  6 +import io.netty.channel.ChannelOption;
  7 +import io.netty.channel.nio.NioEventLoopGroup;
  8 +import io.netty.channel.socket.SocketChannel;
  9 +import io.netty.channel.socket.nio.NioServerSocketChannel;
  10 +import org.shadowsocks.config.Config;
  11 +import org.shadowsocks.crypto.CryptoFactory;
  12 +import org.shadowsocks.handler.server.AddressHandler;
  13 +import org.slf4j.Logger;
  14 +import org.slf4j.LoggerFactory;
  15 +
  16 +
  17 +public class ShadowSocksServer {
  18 +
  19 + private static Logger logger = LoggerFactory.getLogger(ShadowSocksServer.class);
  20 + Config config;
  21 + public ShadowSocksServer(Config config){
  22 + this.config = config;
  23 + }
  24 +
  25 + public void start() throws InterruptedException {
  26 + NioEventLoopGroup group = new NioEventLoopGroup(2);
  27 + ServerBootstrap bootstrap = new ServerBootstrap();
  28 + try {
  29 + bootstrap.group(group)
  30 + .channel(NioServerSocketChannel.class)
  31 + .localAddress(config.getServerPort())
  32 + .option(ChannelOption.SO_TIMEOUT, config.getTimeout())
  33 + .childHandler(new ChannelInitializer<SocketChannel>() {
  34 + @Override
  35 + protected void initChannel(SocketChannel socketChannel) throws Exception {
  36 + socketChannel.pipeline().addLast(new AddressHandler(CryptoFactory.create(config.getMethod(),
  37 + config.getPassword())));
  38 + }
  39 + });
  40 + ChannelFuture channelFuture = bootstrap.bind().sync();
  41 + logger.info("started and listen on " + channelFuture.channel().localAddress());
  42 + channelFuture.channel().closeFuture().sync();
  43 +
  44 + } finally {
  45 + group.shutdownGracefully();
  46 + }
  47 +
  48 + }
  49 +}
  1 +package org.shadowsocks;
  2 +
  3 +
  4 +import io.netty.bootstrap.ServerBootstrap;
  5 +import io.netty.channel.ChannelFuture;
  6 +import io.netty.channel.ChannelInitializer;
  7 +import io.netty.channel.EventLoopGroup;
  8 +import io.netty.channel.nio.NioEventLoopGroup;
  9 +import io.netty.channel.socket.SocketChannel;
  10 +import io.netty.channel.socket.nio.NioServerSocketChannel;
  11 +import io.netty.handler.codec.socksx.v5.Socks5CommandRequestDecoder;
  12 +import io.netty.handler.codec.socksx.v5.Socks5InitialRequestDecoder;
  13 +
  14 +import io.netty.handler.codec.socksx.v5.Socks5ServerEncoder;
  15 +import org.shadowsocks.config.Config;
  16 +import org.shadowsocks.handler.local.*;
  17 +import org.slf4j.Logger;
  18 +import org.slf4j.LoggerFactory;
  19 +
  20 +
  21 +public class ShadowsocksLocal {
  22 +
  23 + private static Logger logger = LoggerFactory.getLogger(ShadowSocksServer.class);
  24 + private Config config;
  25 + public ShadowsocksLocal(Config config){
  26 + this.config = config;
  27 + }
  28 + public void start() throws InterruptedException{
  29 + EventLoopGroup worker = new NioEventLoopGroup(1);
  30 + EventLoopGroup boss = new NioEventLoopGroup();
  31 + ServerBootstrap bootstrap = new ServerBootstrap();
  32 + try{
  33 + bootstrap.group(worker,boss)
  34 + .localAddress(config.getLocalPort())
  35 + .channel(NioServerSocketChannel.class)
  36 + .childHandler(new ChannelInitializer<SocketChannel>() {
  37 + @Override
  38 + protected void initChannel(SocketChannel ch) {
  39 + ch.pipeline().addLast(Socks5ServerEncoder.DEFAULT);
  40 + ch.pipeline().addLast(new Socks5InitialRequestDecoder());
  41 + ch.pipeline().addLast(new Socks5InitialRequestHandler());
  42 + ch.pipeline().addLast(new Socks5CommandRequestDecoder());
  43 + ch.pipeline().addLast(new Socks5CmdRequesthandler(config));
  44 + }
  45 + });
  46 + ChannelFuture futrue = bootstrap.bind().sync();
  47 + logger.info("connected local port:" + config.getLocalPort());
  48 + futrue.channel().closeFuture().sync();
  49 + }
  50 + finally {
  51 + worker.shutdownGracefully();
  52 + boss.shutdownGracefully();
  53 + }
  54 + }
  55 +}
  1 +/*
  2 + * Copyright 2016 Author:NU11 bestoapache@gmail.com
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.shadowsocks.auth;
  17 +
  18 +public class AuthException extends Exception
  19 +{
  20 + private static final long serialVersionUID = 1L;
  21 +
  22 + public AuthException(String message){
  23 + super(message);
  24 + }
  25 + public AuthException(Exception e){
  26 + super(e);
  27 + }
  28 +}
  1 +/*
  2 + * Copyright 2016 Author:NU11 bestoapache@gmail.com
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.shadowsocks.auth;
  17 +
  18 +import javax.crypto.Mac;
  19 +import javax.crypto.spec.SecretKeySpec;
  20 +import java.security.InvalidKeyException;
  21 +import java.security.NoSuchAlgorithmException;
  22 +import java.util.Arrays;
  23 +
  24 +
  25 +public class HmacSHA1 extends SSAuth{
  26 +
  27 + private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
  28 +
  29 + public static final int AUTH_LEN = 10;
  30 +
  31 + @Override
  32 +
  33 + public byte[] doAuth(byte[] key, byte [] data) throws AuthException
  34 + {
  35 + try{
  36 + SecretKeySpec signingKey = new SecretKeySpec(key, HMAC_SHA1_ALGORITHM);
  37 + Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
  38 + mac.init(signingKey);
  39 + byte [] original_result;
  40 + byte [] result = new byte[AUTH_LEN];
  41 + original_result = mac.doFinal(data);
  42 + System.arraycopy(original_result, 0, result, 0, AUTH_LEN);
  43 + return result;
  44 + }catch(NoSuchAlgorithmException | InvalidKeyException e){
  45 + throw new AuthException(e);
  46 + }
  47 + }
  48 +
  49 + @Override
  50 + public boolean doAuth(byte[] key, byte [] data, byte [] expect) throws AuthException
  51 + {
  52 + return Arrays.equals(expect, doAuth(key, data));
  53 + }
  54 +}
  1 +/*
  2 + * Copyright 2016 Author:NU11 bestoapache@gmail.com
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.shadowsocks.auth;
  17 +
  18 +import java.nio.ByteBuffer;
  19 +
  20 +/**
  21 + * Auth base class
  22 + */
  23 +public abstract class SSAuth{
  24 +
  25 + public abstract byte [] doAuth(byte[] key, byte[] data) throws AuthException;
  26 + public abstract boolean doAuth(byte[] key, byte[] data, byte[] auth) throws AuthException;
  27 +
  28 + public static byte [] prepareKey(byte [] i, int c){
  29 + byte [] key = new byte[i.length + 4];
  30 + ByteBuffer b = ByteBuffer.allocate(4);
  31 + b.putInt(c);
  32 + System.arraycopy(i, 0, key, 0, i.length);
  33 + System.arraycopy(b.array(), 0, key, i.length, 4);
  34 + return key;
  35 + }
  36 +
  37 + public static byte [] prepareKey(byte [] i, byte [] k){
  38 + byte [] key = new byte[i.length + k.length];
  39 + System.arraycopy(i, 0, key, 0, i.length);
  40 + System.arraycopy(k, 0, key, i.length, k.length);
  41 + return key;
  42 + }
  43 +}
  1 +package org.shadowsocks.config;
  2 +
  3 +public abstract class BaseConfig implements Config{
  4 +
  5 + private RealConfig config;
  6 + public BaseConfig(Object source){
  7 + this.config = loadConfig(source);
  8 + }
  9 +
  10 +
  11 + @Override
  12 + public String getServerAddress() {
  13 + return config.server;
  14 + }
  15 +
  16 + @Override
  17 + public int getServerPort() {
  18 + return config.server_port;
  19 + }
  20 +
  21 + @Override
  22 + public String getLocalAddress() {
  23 + return config.local_address;
  24 + }
  25 +
  26 + @Override
  27 + public int getLocalPort() {
  28 + return config.local_port;
  29 + }
  30 +
  31 + @Override
  32 + public int getTimeout() {
  33 + return config.timeout;
  34 + }
  35 +
  36 + @Override
  37 + public String getMethod() {
  38 + return config.method;
  39 + }
  40 +
  41 + @Override
  42 + public String getPassword() {
  43 + return config.password;
  44 + }
  45 +
  46 + public RealConfig getConfig(){
  47 + return this.config;
  48 + }
  49 +
  50 +}
  1 +package org.shadowsocks.config;
  2 +
  3 +public interface Config {
  4 + String getServerAddress();
  5 + int getServerPort();
  6 + int getLocalPort();
  7 + String getLocalAddress();
  8 + String getPassword();
  9 + int getTimeout();
  10 + String getMethod();
  11 + RealConfig loadConfig(Object source);
  12 +
  13 +}
  1 +package org.shadowsocks.config;
  2 +
  3 +public class ConfigFactory {
  4 + public static Config getConfig(String path){
  5 + return new JsonConfig(path);
  6 +
  7 + }
  8 +}
  1 +package org.shadowsocks.config;
  2 +
  3 +import com.google.gson.Gson;
  4 +import com.google.gson.stream.JsonReader;
  5 +import java.io.*;
  6 +
  7 +
  8 +
  9 +public class JsonConfig extends BaseConfig {
  10 +
  11 + public JsonConfig(String path){
  12 + super(path);
  13 + }
  14 +
  15 + @Override
  16 + public RealConfig loadConfig(Object path) {
  17 + Gson gson = new Gson();
  18 + RealConfig config = new RealConfig();
  19 + try{
  20 +
  21 + JsonReader reader = new JsonReader(new FileReader((String)path));
  22 + config = gson.fromJson(reader,RealConfig.class);
  23 + }
  24 + catch (IOException e){
  25 + e.printStackTrace();
  26 + }
  27 + return config;
  28 + }
  29 +
  30 +
  31 +
  32 + public static void main(String[] args){
  33 + String path = "/home/thales/config.json";
  34 + Config config = new JsonConfig(path);
  35 + System.out.println(new Gson().toJsonTree(((JsonConfig) config).getConfig()));
  36 + }
  37 +}
  1 +package org.shadowsocks.config;
  2 +
  3 +public class PropertiesConfig extends BaseConfig{
  4 + public PropertiesConfig(String path){
  5 + super(path);
  6 + }
  7 + @Override
  8 + public RealConfig loadConfig(Object path) {
  9 + return new RealConfig();
  10 + }
  11 +}
  1 +package org.shadowsocks.config;
  2 +
  3 +public class RealConfig {
  4 + public String server;
  5 + public int server_port;
  6 + public String local_address;
  7 + public int local_port;
  8 + public int timeout;
  9 + public String method;
  10 + public String password;
  11 +}
  1 +/*
  2 + * Copyright 2016 Author:NU11 bestoapache@gmail.com
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.shadowsocks.crypto;
  17 +
  18 +import org.bouncycastle.crypto.StreamBlockCipher;
  19 +import org.bouncycastle.crypto.StreamCipher;
  20 +import org.bouncycastle.crypto.engines.AESEngine;
  21 +import org.bouncycastle.crypto.modes.CFBBlockCipher;
  22 +import org.bouncycastle.crypto.modes.OFBBlockCipher;
  23 +import org.bouncycastle.crypto.params.KeyParameter;
  24 +import org.bouncycastle.crypto.params.ParametersWithIV;
  25 +
  26 +import java.io.ByteArrayOutputStream;
  27 +
  28 +/**
  29 + * AES Crypt implementation
  30 + */
  31 +public class AESCrypto extends BaseCrypto {
  32 +
  33 + public final static String CIPHER_AES_128_CFB = "aes-128-cfb";
  34 + public final static String CIPHER_AES_192_CFB = "aes-192-cfb";
  35 + public final static String CIPHER_AES_256_CFB = "aes-256-cfb";
  36 + public final static String CIPHER_AES_128_OFB = "aes-128-ofb";
  37 + public final static String CIPHER_AES_192_OFB = "aes-192-ofb";
  38 + public final static String CIPHER_AES_256_OFB = "aes-256-ofb";
  39 +
  40 + private final static int IV_LENGTH = 16;
  41 +
  42 + public AESCrypto(String name, String password) throws CryptoException {
  43 + super(name, password);
  44 + }
  45 +
  46 + @Override
  47 + public int getIVLength() {
  48 + return IV_LENGTH;
  49 + }
  50 +
  51 + @Override
  52 + public int getKeyLength() {
  53 + if(mName.equals(CIPHER_AES_128_CFB) || mName.equals(CIPHER_AES_128_OFB)) {
  54 + return 16;
  55 + }
  56 + else if (mName.equals(CIPHER_AES_192_CFB) || mName.equals(CIPHER_AES_192_OFB)) {
  57 + return 24;
  58 + }
  59 + else if (mName.equals(CIPHER_AES_256_CFB) || mName.equals(CIPHER_AES_256_OFB)) {
  60 + return 32;
  61 + }
  62 + return 0;
  63 + }
  64 +
  65 + protected StreamBlockCipher getCipher(boolean isEncrypted) throws CryptoException
  66 + {
  67 + AESEngine engine = new AESEngine();
  68 + StreamBlockCipher cipher;
  69 +
  70 + if (mName.equals(CIPHER_AES_128_CFB)) {
  71 + cipher = new CFBBlockCipher(engine, getIVLength() * 8);
  72 + }
  73 + else if (mName.equals(CIPHER_AES_192_CFB)) {
  74 + cipher = new CFBBlockCipher(engine, getIVLength() * 8);
  75 + }
  76 + else if (mName.equals(CIPHER_AES_256_CFB)) {
  77 + cipher = new CFBBlockCipher(engine, getIVLength() * 8);
  78 + }
  79 + else if (mName.equals(CIPHER_AES_128_OFB)) {
  80 + cipher = new OFBBlockCipher(engine, getIVLength() * 8);
  81 + }
  82 + else if (mName.equals(CIPHER_AES_192_OFB)) {
  83 + cipher = new OFBBlockCipher(engine, getIVLength() * 8);
  84 + }
  85 + else if (mName.equals(CIPHER_AES_256_OFB)) {
  86 + cipher = new OFBBlockCipher(engine, getIVLength() * 8);
  87 + }
  88 + else {
  89 + throw new CryptoException("Invalid AlgorithmParameter: " + mName);
  90 + }
  91 +
  92 +
  93 + return cipher;
  94 + }
  95 +
  96 + @Override
  97 + protected StreamCipher createCipher(byte[] iv, boolean encrypt) throws CryptoException
  98 + {
  99 + StreamBlockCipher c = getCipher(encrypt);
  100 + ParametersWithIV parameterIV = new ParametersWithIV(new KeyParameter(mKey), iv, 0, mIVLength);
  101 + c.init(encrypt, parameterIV);
  102 + return c;
  103 + }
  104 +
  105 + @Override
  106 + protected void process(byte[] in, ByteArrayOutputStream out, boolean encrypt){
  107 + int size;
  108 + byte[] buffer = new byte[in.length];
  109 + StreamBlockCipher cipher;
  110 + if (encrypt){
  111 + cipher = (StreamBlockCipher)mEncryptCipher;
  112 + }else{
  113 + cipher = (StreamBlockCipher)mDecryptCipher;
  114 + }
  115 + size = cipher.processBytes(in, 0, in.length, buffer, 0);
  116 + out.write(buffer, 0, size);
  117 + }
  118 +}
  1 +/*
  2 + * Copyright 2016 Author:NU11 bestoapache@gmail.com
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.shadowsocks.crypto;
  17 +
  18 +import org.bouncycastle.crypto.StreamCipher;
  19 +
  20 +import java.io.ByteArrayOutputStream;
  21 +import java.io.IOException;
  22 +
  23 +/**
  24 + * Crypt base class implementation
  25 + */
  26 +public abstract class BaseCrypto implements SSCrypto
  27 +{
  28 +
  29 + protected abstract StreamCipher createCipher(byte[] iv, boolean encrypt) throws CryptoException;
  30 + protected abstract void process(byte[] in, ByteArrayOutputStream out, boolean encrypt);
  31 +
  32 + protected final String mName;
  33 + protected final byte[] mKey;
  34 + protected final int mIVLength;
  35 + protected final int mKeyLength;
  36 +
  37 + protected StreamCipher mEncryptCipher = null;
  38 + protected StreamCipher mDecryptCipher = null;
  39 +
  40 + protected byte[] mEncryptIV;
  41 + protected byte[] mDecryptIV;
  42 +
  43 + // One SSCrypto could only do one decrypt/encrypt at the same time.
  44 + protected ByteArrayOutputStream mData;
  45 +
  46 + private final byte [] mLock = new byte[0];
  47 +
  48 + public BaseCrypto(String name, String password) throws CryptoException
  49 + {
  50 + mName = name.toLowerCase();
  51 + mIVLength = getIVLength();
  52 + mKeyLength = getKeyLength();
  53 + if (mKeyLength == 0) {
  54 + throw new CryptoException("Unsupport method: " + mName);
  55 + }
  56 + mKey = Utils.getKey(password, mKeyLength, mIVLength);
  57 + mData = new ByteArrayOutputStream();
  58 + }
  59 +
  60 + public byte [] getKey(){
  61 + return mKey;
  62 + }
  63 +
  64 + public byte [] getIV(boolean encrypt){
  65 + if (encrypt){
  66 + if (mEncryptIV == null){
  67 + mEncryptIV = Utils.randomBytes(mIVLength);
  68 + }
  69 + return mEncryptIV;
  70 + }else
  71 + return mDecryptIV;
  72 + }
  73 +
  74 + private byte [] encryptLocked(byte[] in) throws CryptoException
  75 + {
  76 + mData.reset();
  77 + if (mEncryptCipher == null) {
  78 + mEncryptIV = getIV(true);
  79 + mEncryptCipher = createCipher(mEncryptIV, true);
  80 + try {
  81 + mData.write(mEncryptIV);
  82 + } catch (IOException e) {
  83 + throw new CryptoException(e);
  84 + }
  85 + }
  86 + process(in, mData, true);
  87 + return mData.toByteArray();
  88 + }
  89 +
  90 + @Override
  91 + public byte [] encrypt(byte[] in, int length) throws CryptoException
  92 + {
  93 + synchronized(mLock) {
  94 + if (length != in.length){
  95 + byte[] data = new byte[length];
  96 + System.arraycopy(in, 0, data, 0, length);
  97 + return encryptLocked(data);
  98 + }else{
  99 + return encryptLocked(in);
  100 + }
  101 + }
  102 + }
  103 +
  104 + private byte[] decryptLocked(byte[] in) throws CryptoException
  105 + {
  106 + byte[] data;
  107 + mData.reset();
  108 + if (mDecryptCipher == null) {
  109 + mDecryptCipher = createCipher(in, false);
  110 + mDecryptIV = new byte[mIVLength];
  111 + data = new byte[in.length - mIVLength];
  112 + System.arraycopy(in, 0, mDecryptIV, 0, mIVLength);
  113 + System.arraycopy(in, mIVLength, data, 0, in.length - mIVLength);
  114 + } else {
  115 + data = in;
  116 + }
  117 + process(data, mData, false);
  118 + return mData.toByteArray();
  119 + }
  120 +
  121 + @Override
  122 + public byte [] decrypt(byte[] in, int length) throws CryptoException
  123 + {
  124 + synchronized(mLock) {
  125 + if (length != in.length) {
  126 + byte[] data = new byte[length];
  127 + System.arraycopy(in, 0, data, 0, length);
  128 + return decryptLocked(data);
  129 + }else{
  130 + return decryptLocked(in);
  131 + }
  132 + }
  133 + }
  134 +}
  1 +/*
  2 + * Copyright 2016 Author:NU11 bestoapache@gmail.com
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.shadowsocks.crypto;
  17 +
  18 +import org.bouncycastle.crypto.StreamCipher;
  19 +import org.bouncycastle.crypto.engines.ChaCha7539Engine;
  20 +import org.bouncycastle.crypto.engines.ChaChaEngine;
  21 +import org.bouncycastle.crypto.params.KeyParameter;
  22 +import org.bouncycastle.crypto.params.ParametersWithIV;
  23 +
  24 +import java.io.ByteArrayOutputStream;
  25 +
  26 +/**
  27 + * Chacha20 Crypt implementation
  28 + */
  29 +public class Chacha20Crypto extends BaseCrypto {
  30 +
  31 + private final static String CIPHER_CHACHA20 = "chacha20";
  32 + private final static String CIPHER_CHACHA20_IETF = "chacha20-ietf";
  33 +
  34 + private final static int IV_LENGTH = 8;
  35 + private final static int IV_IETF_LENGTH = 12;
  36 +
  37 + private final static int KEY_LENGTH = 32;
  38 +
  39 + public Chacha20Crypto(String name, String password) throws CryptoException {
  40 + super(name, password);
  41 + }
  42 +
  43 + @Override
  44 + public int getIVLength() {
  45 + if (mName.equals(CIPHER_CHACHA20_IETF)) {
  46 + return IV_IETF_LENGTH;
  47 + } else {
  48 + return IV_LENGTH;
  49 + }
  50 + }
  51 +
  52 + @Override
  53 + public int getKeyLength() {
  54 + if (mName.equals(CIPHER_CHACHA20) || mName.equals(CIPHER_CHACHA20_IETF)) {
  55 + return KEY_LENGTH;
  56 + }
  57 + return 0;
  58 + }
  59 +
  60 + @Override
  61 + protected StreamCipher createCipher(byte[] iv, boolean encrypt) throws CryptoException
  62 + {
  63 + StreamCipher c;
  64 + if (mName.equals(CIPHER_CHACHA20_IETF)) {
  65 + c = new ChaCha7539Engine();
  66 + } else {
  67 + c = new ChaChaEngine();
  68 + }
  69 + ParametersWithIV parameterIV = new ParametersWithIV(new KeyParameter(mKey), iv, 0, mIVLength);
  70 + c.init(encrypt, parameterIV);
  71 + return c;
  72 + }
  73 +
  74 + @Override
  75 + protected void process(byte[] in, ByteArrayOutputStream out, boolean encrypt){
  76 + int size;
  77 + byte[] buffer = new byte[in.length];
  78 + StreamCipher cipher;
  79 + if (encrypt){
  80 + cipher = mEncryptCipher;
  81 + }else{
  82 + cipher = mDecryptCipher;
  83 + }
  84 + size = cipher.processBytes(in, 0, in.length, buffer, 0);
  85 + out.write(buffer, 0, size);
  86 + }
  87 +}
  1 +/*
  2 + * Copyright 2016 Author:NU11 bestoapache@gmail.com
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.shadowsocks.crypto;
  17 +
  18 +public class CryptoException extends Exception
  19 +{
  20 + private static final long serialVersionUID = 1L;
  21 +
  22 + public CryptoException(String message){
  23 + super(message);
  24 + }
  25 + public CryptoException(Exception e){
  26 + super(e);
  27 + }
  28 +}
  1 +/*
  2 + * Copyright 2016 Author:NU11 bestoapache@gmail.com
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.shadowsocks.crypto;
  17 +
  18 +public class CryptoFactory{
  19 +
  20 + private static final String AES = "aes";
  21 + private static final String CHACHA20 = "chacha20";
  22 +
  23 + public static SSCrypto create(String name, String password) throws CryptoException
  24 + {
  25 + String cipherName = name.toLowerCase();
  26 + if (cipherName.startsWith(AES)) {
  27 + return new AESCrypto(name, password);
  28 + }else if (cipherName.startsWith(CHACHA20)) {
  29 + return new Chacha20Crypto(name, password);
  30 + }else{
  31 + throw new CryptoException("Unsupport method: " + name);
  32 + }
  33 + }
  34 +}
  1 +/*
  2 + * Copyright 2016 Author:NU11 bestoapache@gmail.com
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.shadowsocks.crypto;
  17 +
  18 +/**
  19 + * Interface of crypt
  20 + */
  21 +public interface SSCrypto {
  22 + byte [] encrypt(byte[] data, int length) throws CryptoException;
  23 + byte [] decrypt(byte[] data, int length) throws CryptoException;
  24 + int getIVLength();
  25 + int getKeyLength();
  26 + byte [] getIV(boolean encrypt);
  27 + byte [] getKey();
  28 +}
  1 +/*
  2 + * Copyright 2016 Author:NU11 bestoapache@gmail.com
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.shadowsocks.crypto;
  17 +
  18 +import java.io.UnsupportedEncodingException;
  19 +import java.security.MessageDigest;
  20 +import java.security.NoSuchAlgorithmException;
  21 +import java.security.SecureRandom;
  22 +
  23 +public class Utils{
  24 +
  25 + /**
  26 + * Thanks go to Ola Bini for releasing this source on his blog.
  27 + * The source was obtained from <a href="http://olabini.com/blog/tag/evp_bytestokey/">here</a> .
  28 + */
  29 + private static byte[][] EVP_BytesToKey(int key_len, int iv_len, MessageDigest md, byte[] salt, byte[] data, int count) {
  30 + byte[][] both = new byte[2][];
  31 + byte[] key = new byte[key_len];
  32 + int key_ix = 0;
  33 + byte[] iv = new byte[iv_len];
  34 + int iv_ix = 0;
  35 + both[0] = key;
  36 + both[1] = iv;
  37 + byte[] md_buf = null;
  38 + int nkey = key_len;
  39 + int niv = iv_len;
  40 + int i = 0;
  41 + if (data == null) {
  42 + return both;
  43 + }
  44 + int addmd = 0;
  45 + for (;;) {
  46 + md.reset();
  47 + if (addmd++ > 0) {
  48 + md.update(md_buf);
  49 + }
  50 + md.update(data);
  51 + if (null != salt) {
  52 + md.update(salt, 0, 8);
  53 + }
  54 + md_buf = md.digest();
  55 + for (i = 1; i < count; i++) {
  56 + md.reset();
  57 + md.update(md_buf);
  58 + md_buf = md.digest();
  59 + }
  60 + i = 0;
  61 + if (nkey > 0) {
  62 + for (;;) {
  63 + if (nkey == 0)
  64 + break;
  65 + if (i == md_buf.length)
  66 + break;
  67 + key[key_ix++] = md_buf[i];
  68 + nkey--;
  69 + i++;
  70 + }
  71 + }
  72 + if (niv > 0 && i != md_buf.length) {
  73 + for (;;) {
  74 + if (niv == 0)
  75 + break;
  76 + if (i == md_buf.length)
  77 + break;
  78 + iv[iv_ix++] = md_buf[i];
  79 + niv--;
  80 + i++;
  81 + }
  82 + }
  83 + if (nkey == 0 && niv == 0) {
  84 + break;
  85 + }
  86 + }
  87 + for (i = 0; i < md_buf.length; i++) {
  88 + md_buf[i] = 0;
  89 + }
  90 + return both;
  91 + }
  92 +
  93 +
  94 + public static byte[] getKey(String password, int keyLen, int ivLen) throws CryptoException
  95 + {
  96 + MessageDigest md = null;
  97 + byte[] passwordBytes = null;
  98 + byte[][] keyAndIV = null;
  99 + int i = 0;
  100 +
  101 + try{
  102 + md = MessageDigest.getInstance("MD5");
  103 + passwordBytes = password.getBytes("ASCII");
  104 + }catch(NoSuchAlgorithmException | UnsupportedEncodingException e){
  105 + throw new CryptoException(e);
  106 + }
  107 +
  108 + //This key should equal EVP_BytesToKey with no salt and count = 1
  109 + keyAndIV = EVP_BytesToKey(keyLen, ivLen, md, null, passwordBytes, 1);
  110 +
  111 + //Discard the iv.
  112 + return keyAndIV[0];
  113 + }
  114 +
  115 + public static byte[] randomBytes(int size) {
  116 + byte[] bytes = new byte[size];
  117 + new SecureRandom().nextBytes(bytes);
  118 + return bytes;
  119 + }
  120 +
  121 +}
  1 +package org.shadowsocks.handler.local;
  2 +
  3 +
  4 +import io.netty.buffer.ByteBuf;
  5 +import io.netty.buffer.ByteBufUtil;
  6 +import io.netty.buffer.Unpooled;
  7 +import io.netty.channel.ChannelFuture;
  8 +import io.netty.channel.ChannelHandlerContext;
  9 +import io.netty.channel.ChannelInboundHandlerAdapter;
  10 +import io.netty.handler.codec.socksx.v5.DefaultSocks5CommandRequest;
  11 +import org.shadowsocks.crypto.SSCrypto;
  12 +import org.slf4j.Logger;
  13 +import org.slf4j.LoggerFactory;
  14 +
  15 +import java.net.IDN;
  16 +import java.net.Inet4Address;
  17 +import java.net.InetAddress;
  18 +import java.nio.charset.StandardCharsets;
  19 +import java.util.Arrays;
  20 +
  21 +public class Local2RemoteHandler extends ChannelInboundHandlerAdapter {
  22 + private static final Logger logger = LoggerFactory.getLogger(Local2RemoteHandler.class);
  23 +
  24 + private ChannelFuture destChannelFuture;
  25 + private SSCrypto ssCrypto;
  26 + private DefaultSocks5CommandRequest socks5CommandRequest;
  27 + private boolean isProxy = true;
  28 + private boolean addAddress = false;
  29 +
  30 + public Local2RemoteHandler(ChannelFuture destChannelFuture,SSCrypto ssCrypto, DefaultSocks5CommandRequest msg,
  31 + boolean isProxy) {
  32 + this.destChannelFuture = destChannelFuture;
  33 + this.ssCrypto = ssCrypto;
  34 + this.socks5CommandRequest = msg;
  35 + this.isProxy = isProxy;
  36 + }
  37 +
  38 + @Override
  39 + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  40 + if(isProxy){
  41 + ByteBuf buff = (ByteBuf)msg;
  42 + if(!addAddress){
  43 + ByteBuf addressInfo = parseAddress(socks5CommandRequest);
  44 + addressInfo.writeBytes(buff);
  45 + buff = addressInfo;
  46 + addAddress = true;
  47 + }
  48 + byte[] plainTxt = ByteBufUtil.getBytes(buff);
  49 + byte[] encrypt = ssCrypto.encrypt(plainTxt,plainTxt.length);
  50 + logger.info("relay message to remote server from client");
  51 + destChannelFuture.channel().writeAndFlush(Unpooled.copiedBuffer(encrypt));
  52 + }
  53 + else {
  54 + destChannelFuture.channel().writeAndFlush(msg);
  55 + }
  56 +
  57 + }
  58 +
  59 + @Override
  60 + public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  61 + logger.trace("close connection");
  62 + destChannelFuture.channel().close();
  63 + }
  64 +
  65 + private ByteBuf parseAddress (DefaultSocks5CommandRequest msg) throws Exception{
  66 + ByteBuf buff = Unpooled.buffer();
  67 + byte addressType = msg.dstAddrType().byteValue();
  68 + int port = msg.dstPort();
  69 + String host = msg.dstAddr();
  70 + if(addressType == 0x01){
  71 + buff.writeByte(0x01);
  72 + InetAddress address = Inet4Address.getByName(host);
  73 + byte[] addr = address.getAddress();
  74 + buff.writeBytes(addr);
  75 + }
  76 + if(addressType == 0x03){
  77 + buff.writeByte(0x03);
  78 + String address = IDN.toASCII(host);
  79 + byte[] addr = address.getBytes(StandardCharsets.US_ASCII);
  80 + System.out.println(address+","+host+","+addr.length+","+Arrays.toString(addr));
  81 + buff.writeByte(addr.length);
  82 + buff.writeBytes(addr);
  83 + }
  84 + else
  85 + throw new IllegalArgumentException("IP v6 not supported");
  86 + buff.writeShort(port);
  87 + return buff;
  88 + }
  89 +
  90 +}
  1 +package org.shadowsocks.handler.local;
  2 +
  3 +import io.netty.buffer.ByteBuf;
  4 +import io.netty.buffer.ByteBufUtil;
  5 +import io.netty.buffer.Unpooled;
  6 +import io.netty.channel.ChannelHandlerContext;
  7 +import io.netty.channel.ChannelInboundHandlerAdapter;
  8 +import org.shadowsocks.crypto.SSCrypto;
  9 +import org.slf4j.Logger;
  10 +import org.slf4j.LoggerFactory;
  11 +
  12 +import java.nio.charset.StandardCharsets;
  13 +import java.util.Arrays;
  14 +
  15 +public class Remote2LocalHandler extends ChannelInboundHandlerAdapter {
  16 + private static final Logger logger = LoggerFactory.getLogger(Remote2LocalHandler.class);
  17 + private ChannelHandlerContext clientChannelContext;
  18 + private SSCrypto ssCrypto;
  19 + private boolean isProxy = true;
  20 +
  21 + public Remote2LocalHandler(ChannelHandlerContext clientChannelContext, SSCrypto ssCrypto, boolean isProxy) {
  22 + this.clientChannelContext = clientChannelContext;
  23 + this.ssCrypto = ssCrypto;
  24 + this.isProxy = isProxy;
  25 + }
  26 +
  27 + @Override
  28 + public void channelRead(ChannelHandlerContext ctx2, Object remoteMsg) throws Exception {
  29 + if(isProxy){
  30 + ByteBuf buff = (ByteBuf)remoteMsg;
  31 + byte[] encrypted = ByteBufUtil.getBytes(buff);
  32 + byte[] decrypted = ssCrypto.decrypt(encrypted,encrypted.length);
  33 + logger.info("relay response of target server to client");
  34 +// System.out.println("========="+Unpooled.copiedBuffer(decrypted).toString(StandardCharsets.US_ASCII));
  35 + clientChannelContext.writeAndFlush(Unpooled.copiedBuffer(decrypted));
  36 + }
  37 + else {
  38 + clientChannelContext.writeAndFlush(remoteMsg);
  39 + }
  40 + }
  41 +
  42 + @Override
  43 + public void channelInactive(ChannelHandlerContext ctx2) throws Exception {
  44 + logger.trace("close connection to target server");
  45 + clientChannelContext.channel().close();
  46 + }
  47 +}
  1 +package org.shadowsocks.handler.local;
  2 +
  3 +import io.netty.bootstrap.Bootstrap;
  4 +import io.netty.channel.*;
  5 +import io.netty.channel.nio.NioEventLoopGroup;
  6 +import io.netty.channel.socket.SocketChannel;
  7 +import io.netty.channel.socket.nio.NioSocketChannel;
  8 +import io.netty.handler.codec.socksx.v5.*;
  9 +import org.shadowsocks.config.Config;
  10 +import org.shadowsocks.crypto.CryptoFactory;
  11 +import org.shadowsocks.crypto.SSCrypto;
  12 +import org.slf4j.Logger;
  13 +import org.slf4j.LoggerFactory;
  14 +
  15 +/**
  16 + * handle socks5 request
  17 + */
  18 +public class Socks5CmdRequesthandler extends SimpleChannelInboundHandler<DefaultSocks5CommandRequest> {
  19 + private static final Logger logger = LoggerFactory.getLogger(Socks5CmdRequesthandler.class);
  20 + private Config config;
  21 + private EventLoopGroup bossGroup = new NioEventLoopGroup();
  22 + private SSCrypto ssCrypto ;
  23 + private boolean isProxy = true;
  24 +
  25 + public Socks5CmdRequesthandler(Config config){
  26 + this.config = config;
  27 + try{
  28 + ssCrypto = CryptoFactory.create(config.getMethod(),config.getPassword());
  29 + }
  30 + catch (Exception e){
  31 + e.printStackTrace();
  32 + }
  33 + }
  34 +
  35 +
  36 + @Override
  37 + protected void channelRead0(ChannelHandlerContext ctx, DefaultSocks5CommandRequest msg) {
  38 + if(msg.type().equals(Socks5CommandType.CONNECT)) {
  39 + logger.trace("connecting remote server");
  40 +
  41 + Bootstrap bootstrap = new Bootstrap();
  42 + bootstrap.group(bossGroup)
  43 + .channel(NioSocketChannel.class)
  44 + .option(ChannelOption.TCP_NODELAY, true)
  45 + .handler(new ChannelInitializer<SocketChannel>() {
  46 + @Override
  47 + protected void initChannel(SocketChannel ch) throws Exception {
  48 + ch.pipeline().addLast(new Remote2LocalHandler(ctx,ssCrypto,isProxy));
  49 + }
  50 + });
  51 + ChannelFuture future;
  52 + if(isProxy){
  53 + future = bootstrap.connect(config.getServerAddress(), config.getServerPort());
  54 + }
  55 + else {
  56 + future = bootstrap.connect(msg.dstAddr(),msg.dstPort());
  57 + }
  58 + future.addListener(new ChannelFutureListener() {
  59 +
  60 + public void operationComplete(final ChannelFuture future) throws Exception {
  61 + if(future.isSuccess()) {
  62 + logger.info("successfully connected remote server");
  63 + ctx.pipeline().addLast(new Local2RemoteHandler(future,ssCrypto,msg,isProxy));
  64 + Socks5CommandResponse commandResponse = new DefaultSocks5CommandResponse(Socks5CommandStatus.SUCCESS, Socks5AddressType.IPv4);
  65 + ctx.writeAndFlush(commandResponse);
  66 + } else {
  67 + Socks5CommandResponse commandResponse = new DefaultSocks5CommandResponse(Socks5CommandStatus.FAILURE, Socks5AddressType.IPv4);
  68 + ctx.writeAndFlush(commandResponse);
  69 + }
  70 + }
  71 +
  72 + });
  73 + } else {
  74 + ctx.fireChannelRead(msg);
  75 + }
  76 + }
  77 +
  78 +
  79 +}
  1 +package org.shadowsocks.handler.local;
  2 +
  3 +import io.netty.channel.ChannelHandlerContext;
  4 +import io.netty.channel.SimpleChannelInboundHandler;
  5 +import io.netty.handler.codec.socksx.SocksVersion;
  6 +import io.netty.handler.codec.socksx.v5.*;
  7 +import org.slf4j.Logger;
  8 +import org.slf4j.LoggerFactory;
  9 +
  10 +public class Socks5InitialRequestHandler extends SimpleChannelInboundHandler<DefaultSocks5InitialRequest> {
  11 + private static final Logger logger = LoggerFactory.getLogger(Socks5InitialRequestHandler.class);
  12 + @Override
  13 + protected void channelRead0(ChannelHandlerContext ctx, DefaultSocks5InitialRequest msg) {
  14 + if(msg.decoderResult().isFailure()) {
  15 + logger.warn("current protocol is not socks5");
  16 + ctx.fireChannelRead(msg);
  17 + } else {
  18 + if(msg.version().equals(SocksVersion.SOCKS5)) {
  19 + Socks5InitialResponse initialResponse = new DefaultSocks5InitialResponse(Socks5AuthMethod.NO_AUTH);
  20 + ctx.writeAndFlush(initialResponse);
  21 + System.out.println(initialResponse);
  22 + }
  23 + }
  24 +// ctx.pipeline().remove(Socks5InitialRequestDecoder.class);
  25 + }
  26 +}
  1 +package org.shadowsocks.handler.server;
  2 +
  3 +
  4 +import io.netty.buffer.ByteBuf;
  5 +import io.netty.buffer.ByteBufUtil;
  6 +import io.netty.buffer.Unpooled;
  7 +import io.netty.channel.ChannelHandlerContext;
  8 +import io.netty.channel.ChannelInboundHandlerAdapter;
  9 +import org.shadowsocks.crypto.SSCrypto;
  10 +import org.slf4j.Logger;
  11 +import org.slf4j.LoggerFactory;
  12 +
  13 +import java.net.InetAddress;
  14 +
  15 +public class AddressHandler extends ChannelInboundHandlerAdapter {
  16 +
  17 + private static Logger logger = LoggerFactory.getLogger(AddressHandler.class);
  18 + private final static int ADDR_TYPE_IPV4 = 1;
  19 + private final static int ADDR_TYPE_HOST = 3;
  20 +
  21 + private final ByteBuf dataQueue = Unpooled.buffer();
  22 + private final SSCrypto ssCrypto;
  23 +
  24 +
  25 + public AddressHandler(SSCrypto ssCrypto) {
  26 + this.ssCrypto = ssCrypto;
  27 + }
  28 +
  29 + @Override
  30 + public void channelActive(ChannelHandlerContext ctx) throws Exception {
  31 + logger.info("connected with {}", ctx.channel());
  32 + }
  33 +
  34 +
  35 + @Override
  36 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  37 + ctx.close();
  38 + }
  39 +
  40 + @Override
  41 + public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  42 + logger.info("disconnected with {}", ctx.channel());
  43 + }
  44 +
  45 + @Override
  46 + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  47 + ByteBuf buff = (ByteBuf) msg;
  48 + if (buff.readableBytes() <= 0) {
  49 + return;
  50 + }
  51 + byte [] array = ByteBufUtil.getBytes(buff);
  52 + byte[] decrypted = ssCrypto.decrypt(array, array.length);
  53 + dataQueue.writeBytes(decrypted);
  54 + if (dataQueue.readableBytes() < 2) {
  55 + return;
  56 + }
  57 + String host = null;
  58 + int port = 0;
  59 + int addressType = dataQueue.getUnsignedByte(0);
  60 + if (addressType == ADDR_TYPE_IPV4) {
  61 + if (dataQueue.readableBytes() < 7) {
  62 + return;
  63 + }
  64 + // addrType(1) + ipv4(4) + port(2)
  65 + dataQueue.readUnsignedByte();
  66 + byte[] ipBytes = new byte[4];
  67 + dataQueue.readBytes(ipBytes);
  68 + host = InetAddress.getByAddress(ipBytes).toString().substring(1);
  69 + port = dataQueue.readShort();
  70 + } else if (addressType == ADDR_TYPE_HOST) {
  71 + int hostLength = dataQueue.getUnsignedByte(1);
  72 + if (dataQueue.readableBytes() < hostLength + 4) {
  73 + return;
  74 + }
  75 + dataQueue.readUnsignedByte();
  76 + dataQueue.readUnsignedByte();
  77 + byte[] hostBytes = new byte[hostLength];
  78 + dataQueue.readBytes(hostBytes);
  79 + host = new String(hostBytes);
  80 + port = dataQueue.readShort();
  81 + } else {
  82 + throw new IllegalStateException("unknown address type: " + addressType);
  83 + }
  84 + ctx.channel().pipeline().addLast(new ClientDataHandler(host, port, ctx, dataQueue, ssCrypto));
  85 + ctx.channel().pipeline().remove(this);
  86 + }
  87 +
  88 +}
  1 +package org.shadowsocks.handler.server;
  2 +
  3 +import io.netty.bootstrap.Bootstrap;
  4 +import io.netty.buffer.ByteBuf;
  5 +import io.netty.buffer.ByteBufUtil;
  6 +import io.netty.buffer.Unpooled;
  7 +import io.netty.channel.*;
  8 +import io.netty.channel.socket.SocketChannel;
  9 +import io.netty.channel.socket.nio.NioSocketChannel;
  10 +import org.slf4j.Logger;
  11 +import org.slf4j.LoggerFactory;
  12 +import org.shadowsocks.crypto.SSCrypto;
  13 +
  14 +import java.net.InetAddress;
  15 +import java.nio.charset.StandardCharsets;
  16 +import java.util.Arrays;
  17 +import java.util.concurrent.atomic.AtomicReference;
  18 +
  19 +public class ClientDataHandler extends ChannelInboundHandlerAdapter {
  20 +
  21 +
  22 + private static Logger logger = LoggerFactory.getLogger(ClientDataHandler.class);
  23 + private final SSCrypto ssCrypto;
  24 + private final AtomicReference<Channel> remoteChannel = new AtomicReference<>();
  25 + private final ByteBuf clientCache;
  26 +
  27 + public ClientDataHandler(String host, int port, ChannelHandlerContext clientCtx, ByteBuf clientCache, SSCrypto ssCrypto) {
  28 + this.ssCrypto = ssCrypto;
  29 + this.clientCache = clientCache;
  30 + init(host, port, clientCtx, clientCache, ssCrypto);
  31 + }
  32 +
  33 + private void init(String host, int port, final ChannelHandlerContext clientCtx, final ByteBuf byteBuffer, final SSCrypto ssCrypto) {
  34 + Bootstrap bootstrap = new Bootstrap();
  35 + bootstrap.group(clientCtx.channel().eventLoop())
  36 + .channel(NioSocketChannel.class)
  37 + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5 * 1000)
  38 + .handler(new ChannelInitializer<SocketChannel>() {
  39 + @Override
  40 + protected void initChannel(SocketChannel ch) throws Exception {
  41 + ch.pipeline().addLast(new RemoteDataHandler(clientCtx, ssCrypto, byteBuffer));
  42 + }
  43 + });
  44 + try {
  45 + ChannelFuture channelFuture = bootstrap.connect(InetAddress.getByName(host), port);
  46 + channelFuture.addListener(new ChannelFutureListener() {
  47 + @Override
  48 + public void operationComplete(ChannelFuture future) throws Exception {
  49 + if (future.isSuccess()) {
  50 + logger.info("successfully to connect to {}:{}", host, port);
  51 + remoteChannel.set(future.channel());
  52 + } else {
  53 + logger.info("error to connect to {}:{}", host, port);
  54 + clientCtx.close();
  55 + }
  56 + }
  57 + });
  58 + } catch (Exception e) {
  59 + e.printStackTrace();
  60 + clientCtx.close();
  61 + }
  62 + }
  63 +
  64 + @Override
  65 + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  66 + ByteBuf buff = (ByteBuf) msg;
  67 + if (buff.readableBytes() <= 0) {
  68 + return;
  69 + }
  70 + byte[] bytes = ByteBufUtil.getBytes(buff);
  71 + byte[] decrypt = ssCrypto.decrypt(bytes, bytes.length);
  72 + if(remoteChannel.get() == null) {
  73 + clientCache.writeBytes(decrypt);
  74 + } else {
  75 + remoteChannel.get().writeAndFlush(Unpooled.copiedBuffer(decrypt));
  76 + }
  77 + }
  78 +
  79 + @Override
  80 + public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  81 + ctx.close();
  82 + if(remoteChannel.get() != null){
  83 + remoteChannel.get().close();
  84 + }
  85 + }
  86 +
  87 + public static class RemoteDataHandler extends SimpleChannelInboundHandler<ByteBuf> {
  88 +
  89 + private final ChannelHandlerContext clientCtx;
  90 + private final SSCrypto ssCrypto;
  91 + private final ByteBuf byteBuffer;
  92 +
  93 + public RemoteDataHandler(ChannelHandlerContext clientCtx, SSCrypto ssCrypto, ByteBuf byteBuffer) {
  94 + this.clientCtx = clientCtx;
  95 + this.ssCrypto = ssCrypto;
  96 + this.byteBuffer = byteBuffer;
  97 + }
  98 +
  99 + @Override
  100 + public void channelActive(ChannelHandlerContext ctx) throws Exception {
  101 +// System.out.println("!!!!!!!!!!!!!!!!!!!!:"+new String(ByteBufUtil.getBytes(byteBuffer),StandardCharsets.UTF_8));
  102 + ctx.writeAndFlush(byteBuffer);
  103 + }
  104 +
  105 + @Override
  106 + protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
  107 + byte[] bytes = ByteBufUtil.getBytes(msg);
  108 + try {
  109 + byte[] encrypt = ssCrypto.encrypt(bytes, bytes.length);
  110 + System.out.println(ctx.channel()+Arrays.toString(ssCrypto.getIV(true)));
  111 +
  112 + System.out.println("++++++++++++++++:\n"+new String(bytes,StandardCharsets.UTF_8));
  113 +
  114 + clientCtx.writeAndFlush(Unpooled.copiedBuffer(encrypt));
  115 + } catch (Exception e) {
  116 + ctx.close();
  117 + clientCtx.close();
  118 + }
  119 + }
  120 +
  121 + @Override
  122 + public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  123 + ctx.close();
  124 + clientCtx.close();
  125 + }
  126 +
  127 + @Override
  128 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  129 + ctx.close();
  130 + clientCtx.close();
  131 + }
  132 + }
  133 +}
  1 +package org.shadowsocks.util;
  2 +import org.shadowsocks.config.BaseConfig;
  3 +import org.shadowsocks.config.Config;
  4 +import org.shadowsocks.config.JsonConfig;
  5 +import org.shadowsocks.config.RealConfig;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +public class CommandLineParser {
  10 +
  11 + public static Config parse(String[] args)
  12 + {
  13 + RealConfig realConfig = new RealConfig();
  14 + for(int i=0;i<args.length;i++)
  15 + {
  16 + System.out.println(Arrays.toString(args));
  17 + String[] parts = args[i].split("=");
  18 + String key = parts[0];
  19 + String value = parts[1];
  20 +
  21 + if(key.compareTo("config")==0)
  22 + return new JsonConfig(value);
  23 +
  24 + if(key.compareTo("server")==0)
  25 + realConfig.server = value;
  26 +
  27 + if(key.compareTo("server_port")==0)
  28 + realConfig.server_port = Integer.parseInt(value);
  29 +
  30 + if(key.compareTo("local_address")==0)
  31 + realConfig.local_address = value;
  32 + if(key.compareTo("local_port")==0)
  33 + realConfig.local_port = Integer.parseInt(value);
  34 + if(key.compareTo("method")==0)
  35 + realConfig.method = value;
  36 + if(key.compareTo("password")==0)
  37 + realConfig.password = value;
  38 + if(key.compareTo("time_out")==0)
  39 + realConfig.timeout = Integer.parseInt(value);
  40 + }
  41 +
  42 + return new BaseConfig(realConfig) {
  43 + @Override
  44 + public RealConfig loadConfig(Object source) {
  45 + return (RealConfig) source;
  46 + }
  47 + };
  48 + }
  49 +}
  1 +<configuration>
  2 +
  3 + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  4 + <encoder>
  5 + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
  6 + </encoder>
  7 + </appender>
  8 +
  9 + <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  10 +
  11 + <file>logs/info.log</file>
  12 +
  13 + <encoder charset="utf-8">
  14 + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
  15 + </pattern>
  16 + </encoder>
  17 +
  18 + <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
  19 + <fileNamePattern>logs/info.log.%i.gz</fileNamePattern>
  20 + <!-- 最多存留3个文件 -->
  21 + <minIndex>1</minIndex>
  22 + <maxIndex>3</maxIndex>
  23 + </rollingPolicy>
  24 +
  25 + <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
  26 + <!-- 单文件最大50MB -->
  27 + <maxFileSize>50MB</maxFileSize>
  28 + </triggeringPolicy>
  29 +
  30 + </appender>
  31 +
  32 + <root level="info">
  33 + <appender-ref ref="FILE" />
  34 + <appender-ref ref="STDOUT" />
  35 + </root>
  36 +
  37 +</configuration>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +
  3 +<assembly>
  4 + <id>bin</id>
  5 + <!-- 最终打包成一个用于发布的zip文件 -->
  6 + <formats>
  7 + <format>zip</format>
  8 + </formats>
  9 +
  10 + <!-- Adds dependencies to zip package under lib directory -->
  11 + <dependencySets>
  12 + <dependencySet>
  13 + <!--
  14 + 不使用项目的artifact,第三方jar不要解压,打包进zip文件的lib目录
  15 + -->
  16 + <useProjectArtifact>false</useProjectArtifact>
  17 + <outputDirectory>lib</outputDirectory>
  18 + <unpack>false</unpack>
  19 + </dependencySet>
  20 + </dependencySets>
  21 +
  22 + <fileSets>
  23 + <!-- 把项目相关的说明文件,打包进zip文件的根目录 -->
  24 + <fileSet>
  25 + <directory>${project.basedir}</directory>
  26 + <outputDirectory>/</outputDirectory>
  27 + <includes>
  28 + <include>README*</include>
  29 + <include>LICENSE*</include>
  30 + <include>NOTICE*</include>
  31 + </includes>
  32 + </fileSet>
  33 +
  34 + <!-- 把项目的配置文件,打包进zip文件的config目录 -->
  35 + <fileSet>
  36 + <directory>${project.basedir}\src\main\resources\configs</directory>
  37 + <outputDirectory>../configs</outputDirectory>
  38 + <includes>
  39 + <include>*.properties</include>
  40 + </includes>
  41 + </fileSet>
  42 +
  43 + <!-- 把项目的配置文件,提出来 -->
  44 + <fileSet>
  45 + <directory>${project.basedir}\src\main\resources</directory>
  46 + <outputDirectory>/</outputDirectory>
  47 + <includes>
  48 + <include>*.properties</include>
  49 + <include>*.yml</include>
  50 + </includes>
  51 + </fileSet>
  52 +
  53 + <!-- 把项目的脚本文件目录( src/main/scripts )中的启动脚本文件,打包进zip文件的跟目录 -->
  54 + <fileSet>
  55 + <directory>${project.basedir}\bin</directory>
  56 + <outputDirectory></outputDirectory>
  57 + <includes>
  58 + <include>start.*</include>
  59 + <include>stop.*</include>
  60 + </includes>
  61 + </fileSet>
  62 +
  63 + <!-- 把项目自己编译出来的jar文件,打包进zip文件的根目录 -->
  64 + <fileSet>
  65 + <directory>${project.build.directory}</directory>
  66 + <outputDirectory></outputDirectory>
  67 + <includes>
  68 + <include>*.jar</include>
  69 + </includes>
  70 + </fileSet>
  71 + </fileSets>
  72 +</assembly>
  1 +package org.shadowsocks.Util;
  2 +
  3 +import javax.net.ssl.HttpsURLConnection;
  4 +import java.io.BufferedReader;
  5 +import java.io.DataOutputStream;
  6 +import java.io.InputStreamReader;
  7 +import java.net.HttpURLConnection;
  8 +import java.net.URL;
  9 +
  10 +public class HttpUtil {
  11 + private final String USER_AGENT = "Mozilla/5.0";
  12 +
  13 +// public static void main(String[] args) throws Exception {
  14 +//
  15 +// HttpURLConnectionExample http = new HttpURLConnectionExample();
  16 +//
  17 +// System.out.println("Testing 1 - Send Http GET request");
  18 +// http.sendGet();
  19 +//
  20 +// System.out.println("\nTesting 2 - Send Http POST request");
  21 +// http.sendPost();
  22 +//
  23 +// }
  24 +
  25 + // HTTP GET请求
  26 + public void sendGet() throws Exception {
  27 +
  28 + String url = "http://www.baidu.com/search?q=mkyong";
  29 +
  30 + URL obj = new URL(url);
  31 + HttpURLConnection con = (HttpURLConnection) obj.openConnection();
  32 +
  33 + //默认值我GET
  34 + con.setRequestMethod("GET");
  35 +
  36 + //添加请求头
  37 + con.setRequestProperty("User-Agent", USER_AGENT);
  38 +
  39 + int responseCode = con.getResponseCode();
  40 + System.out.println("\nSending 'GET' request to URL : " + url);
  41 + System.out.println("Response Code : " + responseCode);
  42 +
  43 + BufferedReader in = new BufferedReader(
  44 + new InputStreamReader(con.getInputStream()));
  45 + String inputLine;
  46 + StringBuffer response = new StringBuffer();
  47 +
  48 + while ((inputLine = in.readLine()) != null) {
  49 + response.append(inputLine);
  50 + }
  51 + in.close();
  52 +
  53 + //打印结果
  54 + System.out.println(response.toString());
  55 +
  56 + }
  57 +
  58 + // HTTP POST请求
  59 + private void sendPost() throws Exception {
  60 +
  61 + String url = "https://selfsolve.apple.com/wcResults.do";
  62 + URL obj = new URL(url);
  63 + HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
  64 +
  65 + //添加请求头
  66 + con.setRequestMethod("POST");
  67 + con.setRequestProperty("User-Agent", USER_AGENT);
  68 + con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
  69 +
  70 + String urlParameters = "sn=C02G8416DRJM&cn=&locale=&caller=&num=12345";
  71 +
  72 + //发送Post请求
  73 + con.setDoOutput(true);
  74 + DataOutputStream wr = new DataOutputStream(con.getOutputStream());
  75 + wr.writeBytes(urlParameters);
  76 + wr.flush();
  77 + wr.close();
  78 +
  79 + int responseCode = con.getResponseCode();
  80 + System.out.println("\nSending 'POST' request to URL : " + url);
  81 + System.out.println("Post parameters : " + urlParameters);
  82 + System.out.println("Response Code : " + responseCode);
  83 +
  84 + BufferedReader in = new BufferedReader(
  85 + new InputStreamReader(con.getInputStream()));
  86 + String inputLine;
  87 + StringBuffer response = new StringBuffer();
  88 +
  89 + while ((inputLine = in.readLine()) != null) {
  90 + response.append(inputLine);
  91 + }
  92 + in.close();
  93 +
  94 + //打印结果
  95 + System.out.println(response.toString());
  96 +
  97 + }
  98 +}
  1 +package org.shadowsocks.crypto;
  2 +
  3 +import org.junit.Assert;
  4 +import org.junit.Test;
  5 +import java.nio.charset.StandardCharsets;
  6 +import java.util.Arrays;
  7 +import java.util.Random;
  8 +
  9 +import static java.lang.System.arraycopy;
  10 +import static org.shadowsocks.crypto.AESCrypto.CIPHER_AES_256_CFB;
  11 +
  12 +public class AESCryptoTest {
  13 +
  14 +
  15 +
  16 +
  17 +
  18 + @Test
  19 + public void encyptTest() throws Exception {
  20 + byte[] testCase = "hello world, this is pink floyd".getBytes(StandardCharsets.UTF_8);
  21 + AESCrypto cryptoClient = new AESCrypto(CIPHER_AES_256_CFB, "abc123");
  22 + AESCrypto cryptoServer = new AESCrypto(CIPHER_AES_256_CFB, "abc123");
  23 + byte[] en = cryptoClient.encrypt(testCase, testCase.length);
  24 + byte[] de = cryptoServer.decrypt(en, en.length);
  25 + Assert.assertArrayEquals(de, testCase);
  26 + for (int i = 0; i < 100; i++) {
  27 + testCase = Utils.randomBytes(20);
  28 + en = cryptoServer.encrypt(testCase, testCase.length);
  29 + de = cryptoClient.decrypt(en, en.length);
  30 + Assert.assertArrayEquals(de, testCase);
  31 +
  32 + }
  33 +
  34 +
  35 + }
  36 +}
  1 +package org.shadowsocks.socks5;
  2 +import java.net.InetSocketAddress;
  3 +import java.net.PasswordAuthentication;
  4 +import java.net.Proxy;
  5 +
  6 +import okhttp3.OkHttpClient;
  7 +import okhttp3.Request;
  8 +import okhttp3.Response;
  9 +import org.apache.http.client.HttpClient;
  10 +import org.apache.http.client.methods.HttpGet;
  11 +import org.apache.http.impl.client.HttpClients;
  12 +
  13 +
  14 +public class HttpRequestTest {
  15 + public static void main(String[] args) throws Exception {
  16 + final String user = "t";
  17 + final String password = "test";
  18 +
  19 + Proxy proxyTest = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 10000));
  20 +
  21 +// java.net.Authenticator.setDefault(new java.net.Authenticator()
  22 +// {
  23 +// private PasswordAuthentication authentication = new PasswordAuthentication(user, password.toCharArray());
  24 +//
  25 +// @Override
  26 +// protected PasswordAuthentication getPasswordAuthentication()
  27 +// {
  28 +// return authentication;
  29 +// }
  30 +// });
  31 +
  32 +
  33 + OkHttpClient client = new OkHttpClient.Builder().proxy(proxyTest).build();
  34 + Request request = new Request.Builder().url("http://www.baidu.com").build();
  35 + Response response = client.newCall(request).execute();
  36 + System.out.println(response.code());
  37 + System.out.println(response.body());
  38 +
  39 + client.dispatcher().executorService().shutdown();
  40 + client.connectionPool().evictAll();
  41 + }
  42 +
  43 + public void socks5PortTest() throws Exception{
  44 + Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 10000));
  45 + HttpGet get = new HttpGet("http://www.baidu.com/search?hl=en&q=httpclient&btnG=Google+Search&aq=f&oq=");
  46 + HttpClient httpClient = HttpClients.createDefault();
  47 + httpClient.execute(get);
  48 + }
  49 +}
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<module type="JAVA_MODULE" version="4">
  3 + <component name="NewModuleRootManager" inherit-compiler-output="true">
  4 + <exclude-output />
  5 + <content url="file://$MODULE_DIR$">
  6 + <sourceFolder url="file://$MODULE_DIR$/java" isTestSource="true" />
  7 + </content>
  8 + <orderEntry type="inheritedJdk" />
  9 + <orderEntry type="sourceFolder" forTests="false" />
  10 + </component>
  11 +</module>
  1 +#!/usr/bin/env bash
  2 +
  3 +#default value for local port
  4 +local_port=1080
  5 +#default value for cipher method
  6 +method="aes-256-cfb"
  7 +#default value for server port
  8 +server_port=8388
  9 +local_address="127.0.0.1"
  10 +time_out=600
  11 +
  12 +#parse the parameters
  13 +while test $# -gt 0; do
  14 + case "$1" in
  15 + -h|--help)
  16 + echo "A fast tunnel proxy that helps you bypass firewalls."
  17 +
  18 + echo "You can supply configurations via either config file or command line arguments."
  19 +
  20 + echo "Proxy options:"
  21 + echo " -c CONFIG path to config file"
  22 + echo " -s SERVER_ADDR server address"
  23 + echo " -p SERVER_PORT server port, default: 8388"
  24 + echo " -b LOCAL_ADDR local binding address, default: 127.0.0.1"
  25 + echo " -l LOCAL_PORT local port, default: 1080"
  26 + echo " -k PASSWORD password"
  27 + echo " -m METHOD encryption method, default: aes-256-cfb"
  28 + echo " Sodium:"
  29 + echo " chacha20, chacha20-ietf."
  30 + echo " OpenSSL:"
  31 + echo " aes-{128|192|256}-cfb,aes-{128|192|256}-ofb,"
  32 + echo " -t TIMEOUT timeout in seconds, default: 600"
  33 + exit 0
  34 + ;;
  35 + -c)
  36 + shift
  37 + if test $# -gt 0; then
  38 + config=$1
  39 + fi
  40 + shift
  41 + ;;
  42 + -s)
  43 + shift
  44 + if test $# -gt 0; then
  45 + server=$1
  46 + fi
  47 + shift
  48 + ;;
  49 + -p)
  50 + shift
  51 + if test $# -gt 0; then
  52 + server_port=$1
  53 + fi
  54 + shift
  55 + ;;
  56 + -b)
  57 + shift
  58 + if test $# -gt 0; then
  59 + local_address=$1
  60 + fi
  61 + shift
  62 + ;;
  63 + -l)
  64 + shift
  65 + if test $# -gt 0; then
  66 + local_port=$1
  67 + fi
  68 + shift
  69 + ;;
  70 + -k)
  71 + shift
  72 + if test $# -gt 0; then
  73 + password=$1
  74 + fi
  75 + shift
  76 + ;;
  77 + -m)
  78 + shift
  79 + if test $# -gt 0; then
  80 + method=$1
  81 + fi
  82 + shift
  83 + ;;
  84 + -t)
  85 + shift
  86 + if test $# -gt 0; then
  87 + time_out=$1
  88 + fi
  89 + shift
  90 + ;;
  91 + *)
  92 + break
  93 + ;;
  94 + esac
  95 +done
  96 +
  97 +main="LocalMain"
  98 +
  99 +#printing some output to the users
  100 +echo "config: $config"
  101 +if [ -n "$config" ]
  102 +then
  103 + echo "Starting shadowsocks ...";
  104 + java -jar -jar ./target/shadowsocks-java-1.0-SNAPSHOT.jar ${main} config=${config}
  105 +elif [ -z "$server" ]
  106 +then
  107 + echo "please set a server address"
  108 + exit 0
  109 +elif [ -z "$password" ]
  110 +then
  111 + echo "please set a password"
  112 + exit 0
  113 +else
  114 + java -jar ./target/shadowsocks-java-1.0-SNAPSHOT.jar ${main} server=${server} server_port=${server_port}
  115 +local_address=${local_address} local_port=${local_port} method=${method} password=${password}
  116 +fi
  117 +
  118 +
  1 +#!/usr/bin/env bash
  2 +
  3 +#default value for local port
  4 +local_port=1080
  5 +#default value for cipher method
  6 +method="aes-256-cfb"
  7 +#default value for server port
  8 +server_port=8388
  9 +local_address="127.0.0.1"
  10 +time_out=600
  11 +
  12 +#parse the parameters
  13 +while test $# -gt 0; do
  14 + case "$1" in
  15 + -h|--help)
  16 + echo "A fast tunnel proxy that helps you bypass firewalls."
  17 +
  18 + echo "You can supply configurations via either config file or command line arguments."
  19 +
  20 + echo "Proxy options:"
  21 + echo " -c CONFIG path to config file"
  22 + echo " -s SERVER_ADDR server address"
  23 + echo " -p SERVER_PORT server port, default: 8388"
  24 +# echo " -b LOCAL_ADDR local binding address, default: 127.0.0.1"
  25 +# echo " -l LOCAL_PORT local port, default: 1080"
  26 + echo " -k PASSWORD password"
  27 + echo " -m METHOD encryption method, default: aes-256-cfb"
  28 + echo " Sodium:"
  29 + echo " chacha20, chacha20-ietf."
  30 + echo " OpenSSL:"
  31 + echo " aes-{128|192|256}-cfb,aes-{128|192|256}-ofb,"
  32 + echo " -t TIMEOUT timeout in seconds, default: 600"
  33 + exit 0
  34 + ;;
  35 + -c)
  36 + shift
  37 + if test $# -gt 0; then
  38 + config=$1
  39 + fi
  40 + shift
  41 + ;;
  42 + -s)
  43 + shift
  44 + if test $# -gt 0; then
  45 + server=$1
  46 + fi
  47 + shift
  48 + ;;
  49 + -p)
  50 + shift
  51 + if test $# -gt 0; then
  52 + server_port=$1
  53 + fi
  54 + shift
  55 + ;;
  56 + -b)
  57 + shift
  58 + if test $# -gt 0; then
  59 + local_address=$1
  60 + fi
  61 + shift
  62 + ;;
  63 + -l)
  64 + shift
  65 + if test $# -gt 0; then
  66 + local_port=$1
  67 + fi
  68 + shift
  69 + ;;
  70 + -k)
  71 + shift
  72 + if test $# -gt 0; then
  73 + password=$1
  74 + fi
  75 + shift
  76 + ;;
  77 + -m)
  78 + shift
  79 + if test $# -gt 0; then
  80 + method=$1
  81 + fi
  82 + shift
  83 + ;;
  84 + -t)
  85 + shift
  86 + if test $# -gt 0; then
  87 + time_out=$1
  88 + fi
  89 + shift
  90 + ;;
  91 + *)
  92 + break
  93 + ;;
  94 + esac
  95 +done
  96 +
  97 +main="ServerMain"
  98 +#printing some output to the users
  99 +echo "config: $config"
  100 +if [ -n "$config" ]
  101 +then
  102 + echo "Starting shadowsocks ...";
  103 + java -jar ./target/shadowsocks-java-1.0-SNAPSHOT.jar config=${config}
  104 +elif [ -z "$server" ]
  105 +then
  106 + echo "please set a server address"
  107 + exit 0
  108 +elif [ -z "$password" ]
  109 +then
  110 + echo "please set a password"
  111 + exit 0
  112 +else
  113 + java -jar ./target/shadowsocks-java-1.0-SNAPSHOT.jar ${main} server=${server} server_port=${server_port}
  114 +local_address=${local_address} local_port=${local_port} method=${method} password=${password}
  115 +fi
  116 +
  117 +