diff --git a/bin/press/gfw/Client.class b/bin/press/gfw/Client.class index 0c7c84b..0e6a23d 100644 Binary files a/bin/press/gfw/Client.class and b/bin/press/gfw/Client.class differ diff --git a/bin/press/gfw/ClientThread.class b/bin/press/gfw/ClientThread.class index f8b192c..a53bfbb 100644 Binary files a/bin/press/gfw/ClientThread.class and b/bin/press/gfw/ClientThread.class differ diff --git a/bin/press/gfw/Config.class b/bin/press/gfw/Config.class index 645f18a..cbf072a 100644 Binary files a/bin/press/gfw/Config.class and b/bin/press/gfw/Config.class differ diff --git a/bin/press/gfw/DecryptForwardThread.class b/bin/press/gfw/DecryptForwardThread.class index 4e6b8c0..eea0790 100644 Binary files a/bin/press/gfw/DecryptForwardThread.class and b/bin/press/gfw/DecryptForwardThread.class differ diff --git a/bin/press/gfw/Encrypt.class b/bin/press/gfw/Encrypt.class index bc6f627..dcde24e 100644 Binary files a/bin/press/gfw/Encrypt.class and b/bin/press/gfw/Encrypt.class differ diff --git a/bin/press/gfw/EncryptForwardThread.class b/bin/press/gfw/EncryptForwardThread.class index 29ffb69..046d79b 100644 Binary files a/bin/press/gfw/EncryptForwardThread.class and b/bin/press/gfw/EncryptForwardThread.class differ diff --git a/bin/press/gfw/PointThread.class b/bin/press/gfw/PointThread.class index fe31ce2..264d45b 100644 Binary files a/bin/press/gfw/PointThread.class and b/bin/press/gfw/PointThread.class differ diff --git a/bin/press/gfw/Server.class b/bin/press/gfw/Server.class index 3c57fb8..e421c6b 100644 Binary files a/bin/press/gfw/Server.class and b/bin/press/gfw/Server.class differ diff --git a/bin/press/gfw/ServerThread.class b/bin/press/gfw/ServerThread.class index 322b8a4..57f3a67 100644 Binary files a/bin/press/gfw/ServerThread.class and b/bin/press/gfw/ServerThread.class differ diff --git a/bin/press/gfw/Windows$ButtonListener.class b/bin/press/gfw/Windows$ButtonListener.class index 6523c02..35f8ad9 100644 Binary files a/bin/press/gfw/Windows$ButtonListener.class and b/bin/press/gfw/Windows$ButtonListener.class differ diff --git a/bin/press/gfw/Windows$TrayListener.class b/bin/press/gfw/Windows$TrayListener.class index 2251b36..7188db7 100644 Binary files a/bin/press/gfw/Windows$TrayListener.class and b/bin/press/gfw/Windows$TrayListener.class differ diff --git a/bin/press/gfw/Windows$WindowsListener.class b/bin/press/gfw/Windows$WindowsListener.class index 4c855bd..9222f0a 100644 Binary files a/bin/press/gfw/Windows$WindowsListener.class and b/bin/press/gfw/Windows$WindowsListener.class differ diff --git a/bin/press/gfw/Windows.class b/bin/press/gfw/Windows.class index 0cca6d6..6346fec 100644 Binary files a/bin/press/gfw/Windows.class and b/bin/press/gfw/Windows.class differ diff --git a/src/press/gfw/Client.java b/src/press/gfw/Client.java index d015e43..b43d375 100644 --- a/src/press/gfw/Client.java +++ b/src/press/gfw/Client.java @@ -1,5 +1,5 @@ /** -* +* * GFW.Press * Copyright (C) 2016 chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -* +* **/ package press.gfw; @@ -26,11 +26,12 @@ import java.sql.Timestamp; import javax.crypto.SecretKey; +import javax.net.ServerSocketFactory; /** - * + * * GFW.Press客户端 - * + * * @author chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * */ @@ -164,7 +165,7 @@ public synchronized void kill() { /** * 打印信息 - * + * * @param o */ @SuppressWarnings("unused") @@ -178,9 +179,11 @@ private void log(Object o) { /** * 启动客户端 - * + * * @return */ + @Override + @SuppressWarnings("preview") public void run() { if (serverHost == null || (serverHost = serverHost.trim()).length() == 0 || serverPort == 0 || listenPort == 0 || key == null) { @@ -197,7 +200,7 @@ public void run() { try { - listenSocket = new ServerSocket(listenPort); + listenSocket = ServerSocketFactory.getDefault().createServerSocket(listenPort); } catch (IOException ex) { @@ -259,6 +262,7 @@ public void run() { ClientThread clientThread = new ClientThread(agentSocket, serverHost, serverPort, key); + // startVirtualThread(clientThread); clientThread.start(); } diff --git a/src/press/gfw/ClientThread.java b/src/press/gfw/ClientThread.java index 3fb2b08..dea363f 100644 --- a/src/press/gfw/ClientThread.java +++ b/src/press/gfw/ClientThread.java @@ -1,5 +1,5 @@ /** -* +* * GFW.Press * Copyright (C) 2016 chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * @@ -15,22 +15,25 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -* +* **/ package press.gfw; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.InetSocketAddress; import java.net.Socket; import java.sql.Timestamp; import javax.crypto.SecretKey; +import javax.net.SocketFactory; /** - * + * * GFW.Press客户端线程 - * + * * @author chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * */ @@ -46,7 +49,15 @@ public class ClientThread extends PointThread { private Socket serverSocket = null; - private boolean forwarding = false; + private int overN = 0; + + private InputStream agentIn = null; + + private OutputStream agentOut = null; + + private InputStream serverIn = null; + + OutputStream serverOut = null; public ClientThread(Socket agentSocket, String serverHost, int serverPort, SecretKey key) { @@ -61,68 +72,104 @@ public ClientThread(Socket agentSocket, String serverHost, int serverPort, Secre } /** - * 打印信息 - * - * @param o + * 暂停 + * + * @param m */ - private void log(Object o) { + private void _sleep(long m) { - String time = (new Timestamp(System.currentTimeMillis())).toString().substring(0, 19); + try { - System.out.println("[" + time + "] " + o.toString()); + sleep(m); + + } catch (InterruptedException ie) { + + } } - /** - * 关闭所有连接,此线程及转发子线程调用 - */ - public synchronized void over() { + private void close() { - try { + close(agentIn); - serverSocket.close(); + close(serverOut); - } catch (Exception e) { + close(serverIn); - } + close(agentOut); - try { + close(agentSocket); - agentSocket.close(); + close(serverSocket); + + } - } catch (Exception e) { + private void close(Closeable o) { + + if (o == null) { + + return; } - if (forwarding) { + try { + + o.close(); - forwarding = false; + } catch (IOException e) { } } /** - * 启动客户端与服务器之间的转发线程,并对数据进行加密及解密 + * 打印信息 + * + * @param o */ - public void run() { + private void log(Object o) { + + String time = (new Timestamp(System.currentTimeMillis())).toString().substring(0, 19); + + System.out.println("[" + time + "] " + o.toString()); + + } + + @Override + public synchronized void over() { + + overN++; + + if (overN < 2) { + + return; + + } - InputStream agentIn = null; + _sleep(OVER_TIMEOUT); - OutputStream agentOut = null; + close(); - InputStream serverIn = null; + } - OutputStream serverOut = null; + /** + * 启动客户端与服务器之间的转发线程,并对数据进行加密及解密 + */ + @Override + @SuppressWarnings("preview") + public void run() { try { // 连接服务器 - serverSocket = new Socket(serverHost, serverPort); + serverSocket = SocketFactory.getDefault().createSocket(); + serverSocket.connect(new InetSocketAddress(serverHost, serverPort), CONN_TIMEOUT); + + serverSocket.setSoTimeout(SOCK_TIMEOUT); + agentSocket.setSoTimeout(SOCK_TIMEOUT); - // 设置3分钟超时 - serverSocket.setSoTimeout(180000); - agentSocket.setSoTimeout(180000); + serverSocket.setTcpNoDelay(true); + agentSocket.setTcpNoDelay(true); // 打开 keep-alive serverSocket.setKeepAlive(true); @@ -139,19 +186,18 @@ public void run() { log("连接服务器出错:" + serverHost + ":" + serverPort); - over(); + close(); return; } - // 开始转发 - forwarding = true; - EncryptForwardThread forwardServer = new EncryptForwardThread(this, agentIn, serverOut, key); + // startVirtualThread(forwardServer); forwardServer.start(); DecryptForwardThread forwardAgent = new DecryptForwardThread(this, serverIn, agentOut, key); + // startVirtualThread(forwardAgent); forwardAgent.start(); } diff --git a/src/press/gfw/Config.java b/src/press/gfw/Config.java index 2b79074..6f349ff 100644 --- a/src/press/gfw/Config.java +++ b/src/press/gfw/Config.java @@ -1,5 +1,5 @@ /** -* +* * GFW.Press * Copyright (C) 2016 chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -* +* **/ package press.gfw; @@ -33,7 +33,7 @@ /** * GFW.Press配置文件管理 - * + * * @author chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * */ @@ -71,7 +71,7 @@ public Config() { /** * 获取客户端配置文件 - * + * * @return */ public JSONObject getClientConfig() { @@ -82,7 +82,7 @@ public JSONObject getClientConfig() { /** * 字符串转JSON对象 - * + * * @param data * @return */ @@ -114,7 +114,7 @@ public JSONObject getJSON(String data) { /** * 获取服务器配置 - * + * * @return */ public JSONObject getServerConfig() { @@ -151,11 +151,11 @@ public Hashtable getUser() { } - Hashtable users = new Hashtable(lines.length); + Hashtable users = new Hashtable<>(lines.length); - for (int i = 0; i < lines.length; i++) { + for (String line : lines) { - String[] cols = lines[i].trim().split(" "); + String[] cols = line.trim().split(" "); if (cols == null || cols.length < 2 || !(cols[0] = cols[0].trim()).matches("\\d+") || (cols[cols.length - 1] = cols[cols.length - 1].trim()).length() < 8) { @@ -173,7 +173,7 @@ public Hashtable getUser() { /** * 打印信息 - * + * * @param o */ private void log(Object o) { @@ -186,7 +186,7 @@ private void log(Object o) { /** * 读文件内容 - * + * * @param file * @return */ @@ -268,7 +268,7 @@ public String read(File file) { /** * 保存内容到文件 - * + * * @param file * @param text * @return @@ -317,7 +317,7 @@ public boolean save(File file, String text) { /** * 保存客户端配置文件 - * + * * @param json * @return */ @@ -348,7 +348,7 @@ public boolean saveClientConfig(JSONObject json) { /** * 保存服务器配置文件 - * + * * @param json * @return */ diff --git a/src/press/gfw/DecryptForwardThread.java b/src/press/gfw/DecryptForwardThread.java index 4fa5900..9fea3ad 100644 --- a/src/press/gfw/DecryptForwardThread.java +++ b/src/press/gfw/DecryptForwardThread.java @@ -1,5 +1,5 @@ /** -* +* * GFW.Press * Copyright (C) 2016 chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -* +* **/ package press.gfw; @@ -28,7 +28,7 @@ /** * GFW.Press解密及转发线程 - * + * * @author chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * */ @@ -36,26 +36,23 @@ public class DecryptForwardThread extends Thread { private static final int BUFFER_SIZE_MAX = 1024 * 768; // 缓冲区可接受的最大值,768K + private PointThread parent = null; + private InputStream inputStream = null; private OutputStream outputStream = null; - private PointThread parent = null; - private Encrypt aes = null; private SecretKey key = null; /** * 构造方法 - * - * @param parent - * 父线程 - * @param inputStream - * 输入流 - * @param outputStream - * 输出流 - * + * + * @param parent 父线程 + * @param inputStream 输入流 + * @param outputStream 输出流 + * */ public DecryptForwardThread(PointThread parent, InputStream inputStream, OutputStream outputStream, SecretKey key) { @@ -73,7 +70,7 @@ public DecryptForwardThread(PointThread parent, InputStream inputStream, OutputS /** * 打印信息 - * + * * @param o */ @SuppressWarnings("unused") @@ -88,6 +85,7 @@ private void log(Object o) { /** * 解密转发 */ + @Override public void run() { byte[] buffer = null; @@ -98,89 +96,109 @@ public void run() { byte[] decrypt_bytes = null; - try { + while (true) { - while (true) { + buffer = new byte[Encrypt.ENCRYPT_SIZE]; - buffer = new byte[Encrypt.ENCRYPT_SIZE]; + int read_num = 0; - int read_num = inputStream.read(buffer); + try { - if (read_num == -1 || read_num != Encrypt.ENCRYPT_SIZE) { + read_num = inputStream.read(buffer); - break; + } catch (IOException ex) { - } + break; - size_bytes = aes.decrypt(key, buffer); + } - if (size_bytes == null) { + if (read_num != Encrypt.ENCRYPT_SIZE) { - break; // 解密出错,退出 + break; - } + } - sizes = aes.getBlockSizes(size_bytes); + size_bytes = aes.decrypt(key, buffer); - if (sizes == null || sizes.length != 2 || sizes[0] > BUFFER_SIZE_MAX) { + if (size_bytes == null) { - break; + break; // 解密出错,退出 - } + } - int size_count = sizes[0] + sizes[1]; + sizes = aes.getBlockSizes(size_bytes); - buffer = new byte[size_count]; + if (sizes == null || sizes.length != 2 || sizes[0] > BUFFER_SIZE_MAX) { - int read_count = 0; + break; - while (read_count < size_count) { + } - read_num = inputStream.read(buffer, read_count, size_count - read_count); + int size_count = sizes[0] + sizes[1]; + + buffer = new byte[size_count]; + + int read_count = 0; - if (read_num == -1) { + while (read_count < size_count) { - break; + try { - } + read_num = inputStream.read(buffer, read_count, size_count - read_count); + + } catch (IOException ex) { - read_count += read_num; + break; } - if (read_count != size_count) { + if (read_num == -1) { break; } - if (sizes[1] > 0) { // 如果存在噪音数据 + read_count += read_num; + + } - byte[] _buffer = new byte[sizes[0]]; + if (read_count != size_count) { - System.arraycopy(buffer, 0, _buffer, 0, _buffer.length); + break; - decrypt_bytes = aes.decrypt(key, _buffer); + } - } else { + if (sizes[1] > 0) { // 如果存在噪音数据 - decrypt_bytes = aes.decrypt(key, buffer); + byte[] _buffer = new byte[sizes[0]]; - } + System.arraycopy(buffer, 0, _buffer, 0, _buffer.length); - if (decrypt_bytes == null) { + decrypt_bytes = aes.decrypt(key, _buffer); - break; + } else { - } + decrypt_bytes = aes.decrypt(key, buffer); + + } + + if (decrypt_bytes == null) { + + break; + + } + + try { outputStream.write(decrypt_bytes); outputStream.flush(); - } + } catch (IOException ex) { - } catch (IOException ex) { + break; + + } } diff --git a/src/press/gfw/Encrypt.java b/src/press/gfw/Encrypt.java index 13dfa2b..f077aed 100644 --- a/src/press/gfw/Encrypt.java +++ b/src/press/gfw/Encrypt.java @@ -1,5 +1,5 @@ /** -* +* * GFW.Press * Copyright (C) 2016 chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -* +* **/ package press.gfw; @@ -49,7 +49,7 @@ /** * GFW.Press加密及解密管理 - * + * * @author chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * */ @@ -107,15 +107,12 @@ public Encrypt() { /** * 解密 - * - * @param key - * SecretKey - * @param encrypt_bytes - * 头部包含16字节IV的加密数据 - * - * @return - * 解密数据 - * + * + * @param key SecretKey + * @param encrypt_bytes 头部包含16字节IV的加密数据 + * + * @return 解密数据 + * */ public byte[] decrypt(SecretKey key, byte[] encrypt_bytes) { @@ -139,17 +136,13 @@ public byte[] decrypt(SecretKey key, byte[] encrypt_bytes) { /** * 解密 - * - * @param key - * SecretKey - * @param cipher_data - * 加密数据 - * @param IV - * IV - * - * @return - * 解密数据 - * + * + * @param key SecretKey + * @param cipher_data 加密数据 + * @param IV IV + * + * @return 解密数据 + * */ public byte[] decrypt(SecretKey key, byte[] cipher_data, byte[] IV) { @@ -193,15 +186,11 @@ public byte[] decrypt(SecretKey key, byte[] cipher_data, byte[] IV) { /** * 解密文件 - * - * @param key - * SecretKey - * @param src - * 加密的文件 - * @param dest - * 解密后的文件 - * @return - * 解密是否成功 + * + * @param key SecretKey + * @param src 加密的文件 + * @param dest 解密后的文件 + * @return 解密是否成功 */ public boolean decryptFile(SecretKey key, File src, File dest) { @@ -359,15 +348,12 @@ public boolean decryptFile(SecretKey key, File src, File dest) { /** * 加密 - * - * @param key - * SecretKey - * @param data - * 数据 - * - * @return - * 加密数据 - * + * + * @param key SecretKey + * @param data 数据 + * + * @return 加密数据 + * */ public byte[] encrypt(SecretKey key, byte[] data) { @@ -423,17 +409,13 @@ public byte[] encrypt(SecretKey key, byte[] data) { /** * 加密文件 - * - * @param key - * SecretKey - * @param src - * 原文件 - * @param dest - * 加密文件 - * - * @return - * 加密是否成功 - * + * + * @param key SecretKey + * @param src 原文件 + * @param dest 加密文件 + * + * @return 加密是否成功 + * */ public boolean encryptFile(SecretKey key, File src, File dest) { @@ -567,20 +549,18 @@ public boolean encryptFile(SecretKey key, File src, File dest) { /** * 加密网络数据 - * - * @param key - * SecretKey - * - * @param bytes - * 原始数据 - * - * @return - * [加密数据+噪音数据]长度值的加密数据 + [加密数据 + 噪音数据] - * + * + * @param key SecretKey + * + * @param bytes 原始数据 + * + * @return [加密数据+噪音数据]长度值的加密数据 + [加密数据 + 噪音数据] + * */ public byte[] encryptNet(SecretKey key, byte[] bytes) { - if (key == null || bytes == null || bytes.length == 0) { + // if (key == null || bytes == null || bytes.length == 0) { + if (key == null || bytes == null) { return null; @@ -669,13 +649,11 @@ public byte[] encryptNet(SecretKey key, byte[] bytes) { /** * 还原块长度值 - * - * @param bytes - * 块长度字节数组 - * - * @return - * 块长度值 - * + * + * @param bytes 块长度字节数组 + * + * @return 块长度值 + * */ public int getBlockSize(byte[] bytes) { @@ -709,11 +687,9 @@ public int getBlockSize(byte[] bytes) { /** * 生成块长度值的字节数组 - * - * @param size - * 块长度 - * @return - * 块长度值字节数组 + * + * @param size 块长度 + * @return 块长度值字节数组 */ public byte[] getBlockSizeBytes(int size) { @@ -733,15 +709,12 @@ public byte[] getBlockSizeBytes(int size) { /** * 块长度值转换为字节数组 - * - * @param size - * 加密后的数据块总长度值 - * - * @param noise_size - * 加密前的噪音数据块长度值 - * - * @return - * 块长度值字节数组 + * + * @param size 加密后的数据块总长度值 + * + * @param noise_size 加密前的噪音数据块长度值 + * + * @return 块长度值字节数组 */ public byte[] getBlockSizeBytes(int data_size, int noise_size) { @@ -761,9 +734,8 @@ public byte[] getBlockSizeBytes(int data_size, int noise_size) { /** * 从字节数组还原块长度值 - * - * @param bytes - * 长度值字节数组,格式 %08d,%05d + * + * @param bytes 长度值字节数组,格式 %08d,%05d * @return int[2] */ public int[] getBlockSizes(byte[] bytes) { @@ -800,10 +772,9 @@ public int[] getBlockSizes(byte[] bytes) { /** * 生成256位SecretKey - * - * @return - * 256位SecretKey - * + * + * @return 256位SecretKey + * */ public SecretKey getKey() { @@ -813,13 +784,11 @@ public SecretKey getKey() { /** * 生成指定加密位数的AES SecretKey - * - * @param bits - * 加密位数 - * - * @return - * SecretKey - * + * + * @param bits 加密位数 + * + * @return SecretKey + * */ public SecretKey getKey(int bits) { @@ -849,13 +818,11 @@ public SecretKey getKey(int bits) { /** * 使用密码生成SecretKey - * - * @param password - * 密码,必须符合isPassword()要求的标准 - * - * @return - * SecretKey - * + * + * @param password 密码,必须符合isPassword()要求的标准 + * + * @return SecretKey + * */ public SecretKey getPasswordKey(String password) { @@ -883,13 +850,11 @@ public SecretKey getPasswordKey(String password) { /** * 使用SecretKey字符串还原SecretKey - * - * @param stringKey - * SecretKey字符串 - * - * @return - * SecretKey - * + * + * @param stringKey SecretKey字符串 + * + * @return SecretKey + * */ public SecretKey getSecretKey(String stringKey) { @@ -907,9 +872,8 @@ public SecretKey getSecretKey(String stringKey) { /** * 生成指定长度的SecureRandom - * - * @param size - * 指定长度 + * + * @param size 指定长度 * @return */ public byte[] getSecureRandom(int size) { @@ -924,13 +888,11 @@ public byte[] getSecureRandom(int size) { /** * 获取SecretKey的字符串 - * - * @param secretKey - * SecretKey - * - * @return - * SecretKey的字符串 - * + * + * @param secretKey SecretKey + * + * @return SecretKey的字符串 + * */ public String getStringKey(SecretKey secretKey) { @@ -946,13 +908,9 @@ public String getStringKey(SecretKey secretKey) { /** * 检查密码是否合格 - * - * 1、长度至少为八个字符 - * 2、至少包含一个数字 - * 3、至少包含一个大写字母 - * 4、至少包含一个小写字母 - * 5、不得包含空格 - * + * + * 1、长度至少为八个字符 2、至少包含一个数字 3、至少包含一个大写字母 4、至少包含一个小写字母 5、不得包含空格 + * * @param password * @return */ @@ -967,18 +925,16 @@ public boolean isPassword(String password) { return true; /* - * 2、至少包含一个数字 - * 3、至少包含一个大写字母 - * 4、至少包含一个小写字母 - * 5、不得包含空格 + * 2、至少包含一个数字 3、至少包含一个大写字母 4、至少包含一个小写字母 5、不得包含空格 */ - // return password.matches("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}$"); + // return + // password.matches("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}$"); } /** * 打印信息 - * + * * @param o */ private void log(Object o) { diff --git a/src/press/gfw/EncryptForwardThread.java b/src/press/gfw/EncryptForwardThread.java index a71149a..efdf3c5 100644 --- a/src/press/gfw/EncryptForwardThread.java +++ b/src/press/gfw/EncryptForwardThread.java @@ -1,5 +1,5 @@ /** -* +* * GFW.Press * Copyright (C) 2016 chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -* +* **/ package press.gfw; @@ -28,38 +28,35 @@ /** * GFW.Press加密及转发线程 - * + * * @author chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * */ public class EncryptForwardThread extends Thread { - private static final int BUFFER_SIZE_MIN = 1024 * 128; // 缓冲区最小值,128K + private static final int BUFFER_MIN = 1024 * 32; // 缓冲区最小值 - private static final int BUFFER_SIZE_MAX = 1024 * 512; // 缓冲区最大值,512K + private static final int BUFFER_MAX = 1024 * 96; // 缓冲区最大值 - private static final int BUFFER_SIZE_STEP = 1024 * 128; // 缓冲区自动调整的步长值,128K + private static final int BUFFER_STEP = 1024 * 32; // 缓冲区自动调整的步长值 + + private PointThread parent = null; private InputStream inputStream = null; private OutputStream outputStream = null; - private PointThread parent = null; - private Encrypt aes = null; private SecretKey key = null; /** * 构造方法 - * - * @param parent - * 父线程 - * @param inputStream - * 输入流 - * @param outputStream - * 输出流 - * + * + * @param parent 父线程 + * @param inputStream 输入流 + * @param outputStream 输出流 + * */ public EncryptForwardThread(PointThread parent, InputStream inputStream, OutputStream outputStream, SecretKey key) { @@ -77,7 +74,7 @@ public EncryptForwardThread(PointThread parent, InputStream inputStream, OutputS /** * 打印信息 - * + * * @param o */ @SuppressWarnings("unused") @@ -92,59 +89,68 @@ private void log(Object o) { /** * 加密转发 */ + @Override public void run() { - byte[] buffer = new byte[BUFFER_SIZE_MIN]; + byte[] buffer = new byte[BUFFER_MIN]; byte[] read_bytes = null; byte[] encrypt_bytes = null; - try { + while (true) { - while (true) { + int read_num = 0; - int read_num = inputStream.read(buffer); + try { - if (read_num == -1) { + read_num = inputStream.read(buffer); - break; + } catch (IOException ex) { - } + break; - read_bytes = new byte[read_num]; + } + + if (read_num == -1) { + + break; - System.arraycopy(buffer, 0, read_bytes, 0, read_num); + } - encrypt_bytes = aes.encryptNet(key, read_bytes); + if (read_bytes == null || read_bytes.length != read_num) { - if (encrypt_bytes == null) { + read_bytes = new byte[read_num]; - break; // 加密出错,退出 + } - } + System.arraycopy(buffer, 0, read_bytes, 0, read_num); - outputStream.write(encrypt_bytes); + encrypt_bytes = aes.encryptNet(key, read_bytes); - outputStream.flush(); + if (encrypt_bytes == null) { - if (read_num == buffer.length && read_num < BUFFER_SIZE_MAX) { // 自动调整缓冲区大小 + break; // 加密出错,退出 - buffer = new byte[read_num + BUFFER_SIZE_STEP]; + } - // log(this.getName() + " 缓冲区大小自动调整为:" + buffer.length); + try { - } else if (read_num < (buffer.length - BUFFER_SIZE_STEP) && (buffer.length - BUFFER_SIZE_STEP) >= BUFFER_SIZE_MIN) { + outputStream.write(encrypt_bytes); - buffer = new byte[buffer.length - BUFFER_SIZE_STEP]; + outputStream.flush(); - // log(this.getName() + " 缓冲区大小自动调整为:" + +buffer.length); + } catch (IOException ex) { - } + break; } - } catch (IOException ex) { + if (read_num == buffer.length && read_num < BUFFER_MAX) { + + buffer = new byte[read_num + BUFFER_STEP]; + + } } diff --git a/src/press/gfw/PointThread.java b/src/press/gfw/PointThread.java index 83cfd6d..8687377 100644 --- a/src/press/gfw/PointThread.java +++ b/src/press/gfw/PointThread.java @@ -1,5 +1,5 @@ /** -* +* * GFW.Press * Copyright (C) 2016 chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * @@ -15,19 +15,25 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -* +* **/ package press.gfw; /** - * + * * GFW.Press客户端/服务器线程父类 - * + * * @author chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * */ public class PointThread extends Thread { + public static final int CONN_TIMEOUT = 3000; + + public static final int SOCK_TIMEOUT = 3000; + + public final static int OVER_TIMEOUT = 300; + /** * 关闭所有连接,此线程及转发子线程调用 */ diff --git a/src/press/gfw/Server.java b/src/press/gfw/Server.java index 2c4afde..0c27a76 100644 --- a/src/press/gfw/Server.java +++ b/src/press/gfw/Server.java @@ -1,5 +1,5 @@ /** -* +* * GFW.Press * Copyright (C) 2016 chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -* +* **/ package press.gfw; @@ -28,13 +28,14 @@ import java.util.Hashtable; import javax.crypto.SecretKey; +import javax.net.ServerSocketFactory; import org.json.simple.JSONObject; /** - * + * * GFW.Press服务器 - * + * * @author chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * */ @@ -83,7 +84,7 @@ public Server() { /** * 构造方法,用户线程 - * + * * @param proxyHost * @param proxyPort * @param listenPort @@ -113,7 +114,7 @@ public Server(String proxyHost, int proxyPort, int listenPort, String password) /** * 构造方法,用户线程 - * + * * @param proxyHost * @param proxyPort * @param listenPort @@ -127,7 +128,7 @@ public Server(String proxyHost, int proxyPort, String listenPort, String passwor /** * 暂停 - * + * * @param m */ private void _sleep(long m) { @@ -144,7 +145,7 @@ private void _sleep(long m) { /** * 获取密码 - * + * * @return */ public synchronized String getPassword() { @@ -204,7 +205,7 @@ private void loadConfig() { /** * 打印信息 - * + * * @param o */ private void log(Object o) { @@ -218,6 +219,8 @@ private void log(Object o) { /** * 用户线程 */ + @Override + @SuppressWarnings("preview") public void run() { // log("监听端口:" + listenPort); @@ -234,7 +237,7 @@ public void run() { try { - serverSocket = new ServerSocket(listenPort); + serverSocket = ServerSocketFactory.getDefault().createServerSocket(listenPort); } catch (IOException ex) { @@ -282,6 +285,7 @@ public void run() { ServerThread serverThread = new ServerThread(clientSocket, proxyHost, proxyPort, key); + // startVirtualThread(serverThread); serverThread.start(); } @@ -307,6 +311,7 @@ public void run() { /** * 主线程 */ + @SuppressWarnings("preview") public void service() { if (System.currentTimeMillis() - lockFile.lastModified() < 30 * 1000L) { @@ -337,7 +342,7 @@ public void service() { Hashtable users = null; // 用户 - Hashtable threads = new Hashtable(); // 用户线程 + Hashtable threads = new Hashtable<>(); // 用户线程 while (true) { @@ -383,6 +388,7 @@ public void service() { threads.put(threadPort, thread); + // startVirtualThread(thread); thread.start(); } @@ -401,6 +407,7 @@ public void service() { threads.put(userPort, thread); + // startVirtualThread(thread); thread.start(); } diff --git a/src/press/gfw/ServerThread.java b/src/press/gfw/ServerThread.java index 76b7166..5956532 100644 --- a/src/press/gfw/ServerThread.java +++ b/src/press/gfw/ServerThread.java @@ -1,5 +1,5 @@ /** -* +* * GFW.Press * Copyright (C) 2016 chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * @@ -15,22 +15,25 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -* +* **/ package press.gfw; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.InetSocketAddress; import java.net.Socket; import java.sql.Timestamp; import javax.crypto.SecretKey; +import javax.net.SocketFactory; /** - * + * * GFW.Press服务器线程 - * + * * @author chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * */ @@ -46,7 +49,15 @@ public class ServerThread extends PointThread { private SecretKey key = null; - private boolean forwarding = false; + private int overN = 0; + + private InputStream clientIn = null; + + private OutputStream clientOut = null; + + private InputStream proxyIn = null; + + private OutputStream proxyOut = null; public ServerThread(Socket clientSocket, String proxyHost, int proxyPort, SecretKey key) { @@ -61,68 +72,105 @@ public ServerThread(Socket clientSocket, String proxyHost, int proxyPort, Secret } /** - * 打印信息 - * - * @param o + * 暂停 + * + * @param m */ - private void log(Object o) { + private void _sleep(long m) { - String time = (new Timestamp(System.currentTimeMillis())).toString().substring(0, 19); + try { - System.out.println("[" + time + "] " + o.toString()); + sleep(m); + + } catch (InterruptedException ie) { + + } } - /** - * 关闭所有连接,此线程及转发子线程调用 - */ - public synchronized void over() { + private void close() { - try { + close(clientIn); - proxySocket.close(); + close(proxyOut); - } catch (Exception e) { + close(proxyIn); - } + close(clientOut); - try { + close(clientSocket); + + close(proxySocket); + + } - clientSocket.close(); + private void close(Closeable o) { - } catch (Exception e) { + if (o == null) { + + return; } - if (forwarding) { + try { - forwarding = false; + o.close(); + + } catch (IOException e) { } } /** - * 启动服务器与客户端之间的转发线程,并对数据进行加密及解密 + * 打印信息 + * + * @param o */ - public void run() { + private void log(Object o) { + + String time = (new Timestamp(System.currentTimeMillis())).toString().substring(0, 19); + + System.out.println("[" + time + "] " + o.toString()); + + } + + @Override + public synchronized void over() { - InputStream clientIn = null; + overN++; - OutputStream clientOut = null; + if (overN < 2) { - InputStream proxyIn = null; + return; + + } + + _sleep(OVER_TIMEOUT); + + close(); + + } - OutputStream proxyOut = null; + /** + * 启动服务器与客户端之间的转发线程,并对数据进行加密及解密 + */ + @Override + @SuppressWarnings("preview") + public void run() { try { // 连接代理服务器 - proxySocket = new Socket(proxyHost, proxyPort); + proxySocket = SocketFactory.getDefault().createSocket(); - // 设置3分钟超时 - proxySocket.setSoTimeout(180000); - clientSocket.setSoTimeout(180000); + proxySocket.connect(new InetSocketAddress(proxyHost, proxyPort), CONN_TIMEOUT); + + proxySocket.setSoTimeout(SOCK_TIMEOUT); + clientSocket.setSoTimeout(SOCK_TIMEOUT); + + proxySocket.setTcpNoDelay(true); + clientSocket.setTcpNoDelay(true); // 打开 keep-alive proxySocket.setKeepAlive(true); @@ -139,19 +187,18 @@ public void run() { log("连接代理服务器出错:" + proxyHost + ":" + proxyPort); - over(); + close(); return; } - // 开始转发 - forwarding = true; - DecryptForwardThread forwardProxy = new DecryptForwardThread(this, clientIn, proxyOut, key); + // startVirtualThread(forwardProxy); forwardProxy.start(); EncryptForwardThread forwardClient = new EncryptForwardThread(this, proxyIn, clientOut, key); + // startVirtualThread(forwardClient); forwardClient.start(); } diff --git a/src/press/gfw/Windows.java b/src/press/gfw/Windows.java index 6a651a7..9adb0cc 100644 --- a/src/press/gfw/Windows.java +++ b/src/press/gfw/Windows.java @@ -1,5 +1,5 @@ /** -* +* * GFW.Press * Copyright (C) 2016 chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -* +* **/ package press.gfw; @@ -44,9 +44,9 @@ import org.json.simple.JSONObject; /** - * + * * GFW.Press客户端图形界面 - * + * * @author chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * */ @@ -70,91 +70,91 @@ public void actionPerformed(ActionEvent ae) { switch (command) { - case "退出": + case "退出": - setVisible(false); + setVisible(false); - if (tray != null && icon != null) { + if (tray != null && icon != null) { - tray.remove(icon); + tray.remove(icon); - } + } - System.exit(0); + System.exit(0); - break; + break; - case "确定": + case "确定": - setVisible(false); + setVisible(false); - boolean edit = false; + boolean edit = false; - if (!serverHost.equals(serverHostField.getText().trim())) { + if (!serverHost.equals(serverHostField.getText().trim())) { - serverHost = serverHostField.getText().trim(); + serverHost = serverHostField.getText().trim(); - edit = true; + edit = true; - } + } - if (!serverPort.equals(serverPortField.getText().trim())) { + if (!serverPort.equals(serverPortField.getText().trim())) { - serverPort = serverPortField.getText().trim(); + serverPort = serverPortField.getText().trim(); - edit = true; + edit = true; - } + } - String _password = new String(passwordField.getPassword()).trim(); + String _password = new String(passwordField.getPassword()).trim(); - if (!password.equals(_password)) { + if (!password.equals(_password)) { - password = _password; + password = _password; - edit = true; + edit = true; - } + } - // if (!AES256CFB.isPassword(password)) { + // if (!AES256CFB.isPassword(password)) { - // passwordField.setBackground(Color.ORANGE); + // passwordField.setBackground(Color.ORANGE); - // passwordField.setToolTipText("密码需包含大小写字母和数字,至少八个字符。"); + // passwordField.setToolTipText("密码需包含大小写字母和数字,至少八个字符。"); - // } + // } - if (!proxyPort.equals(proxyPortField.getText().trim())) { + if (!proxyPort.equals(proxyPortField.getText().trim())) { - proxyPort = proxyPortField.getText().trim(); + proxyPort = proxyPortField.getText().trim(); - edit = true; + edit = true; - } + } - if (edit) { + if (edit) { - saveConfig(); + saveConfig(); - } + } - start(); + start(); - break; + break; - case "取消": + case "取消": - setVisible(false); + setVisible(false); - serverHostField.setText(serverHost); + serverHostField.setText(serverHost); - serverPortField.setText(serverPort); + serverPortField.setText(serverPort); - passwordField.setText(password); + passwordField.setText(password); - proxyPortField.setText(proxyPort); + proxyPortField.setText(proxyPort); - break; + break; } @@ -441,7 +441,7 @@ private void loadConfig() { /** * 打印信息 - * + * * @param o */ private void log(Object o) { @@ -469,6 +469,7 @@ private void saveConfig() { } + @SuppressWarnings("preview") public void start() { if (client != null && !client.isKill()) { @@ -487,10 +488,9 @@ public void start() { client = new Client(serverHost, serverPort, password, proxyPort); + // Thread.startVirtualThread(client); client.start(); - // log(client.getName()); - } }