Total Pageviews

Tuesday, 19 April 2016

GFW.Press-一款基于java的翻墙程序

欢迎使用 GFW.Press 软件

一、客户端
请访问 http://gfw.press/GFW.Press.msi 下载客户端安装包.
请访问 http://gfw.press 获取连接配置信息
配置填写完成,点击“确定”按钮
设置浏览器的http代理,地址: 127.0.0.1  端口: 3128 (本地机器的这个端口可随便设,比如31281,只要是未被占用的端口就行

如果你的客户端机器是mac或者linux桌面系统,则
git clone https://github.com/chinashiyu/gfw.press
cd gfw.press
bash client.sh
 

如果你遇到出错提示:java.security.InvalidKeyException: Illegal key size ,解决办法:
去掉这种限制需要下载Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files.网址如下。
下载包的readme.txt 有安装说明。就是替换${java_home}/jre/lib/security/ 下面的local_policy.jar和US_export_policy.jar
Most likely you don't have the unlimited strength file installed now.
You may need to download this file:
Install the file in ${java.home}/jre/lib/security/.
参考自:
http://blog.csdn.net/shangpusp/article/details/7416603
http://stackoverflow.com/questions/6481627/java-security-illegal-key-size-or-default-parameters
然后再次运行bash client.sh ,就不会遇到错误了。
二、服务器 以 CentOS 为例: 第一步:下载 gfw.press
git clone https://github.com/chinashiyu/gfw.press

第二步:安装 JDK:
yum install java-1.8.0-openjdk.x86_64 -y 
(如果是debian系统,则apt-get install openjdk-7-jdk -y) 
 
 第三步:安装代理软件:
yum install squid -y
(如果是debian系统,则apt-get install squid3 -y)
 
 第四步:修改连接帐号文件user.txt,
每行表示一个帐号,由 端口号+空格+密码 组成,密码长度至少8位,必需包含大小写字母和数字

第五步:运行
cd gfw.press
bash server.sh
 
root@AR:~/gfw.press# grep -ri 3128 . (在当前目录下,搜索字符串3128)
./readme.txt:设置浏览器代理,地址: 127.0.0.1  端口: 3128
./client.json:{"ServerHost":"69.30.201.106","ServerPort":"","ProxyPort":"3128","Password":""}
./server.json: "ProxyPort":"3128",
./src/press/gfw/Server.java: private int proxyPort = 3128; // 默认为HTTP代理服务器程序的标准端口。(这里的代理服务器程序必须为HTTP代理服务器程序,比如tinyproxy,不能为socks代理服务器程序)
root@AR:~/gfw.press# 
 
可修改./server.json和./src/press/gfw/Server.java这2个文件里的3128端口为其他端口,比如30280,而30280为服务器上的某个http代理服务器程序(比如tinyproxy)所监听的端口号。
 
 请访问 http://twitter.com/chinashiyu 发表意见及建议.

from https://github.com/chinashiyu/gfw.press
------------------------------------------------
 
GFW.Press的安卓手機客户端

暫時大殺器只有2個安卓客戶端支援,一個是官方客戶端,另一個是@postern_overwal
推油開發的多協議第三方客戶端,支持大殺器,暫時是實驗性功能。
官方客戶端只支援能設置HTTP代理的apps,而Postern是VPN模式,可以使用類似iOS下
A.Big.T/Surge/Shadowrocket的規則,或者全局代理,就像影梳的使用方式。
先說石斑魚大爺官方客戶端,下載後安裝,填入所需資料,如圖
然後前往安卓開源市場,下載客戶端,裡面有些可以設置代理的Apps,其中有Twidere
,這個和Twitter官方客戶端一樣,可以設置代理,在手機安裝好後,開啟大殺器客戶端
如圖
然後打開Twidere,撥開選單,點設定
按地球的圖示,點選高級
開啟『為所有網絡請求使用代理』
選取HTTP代理,選取『代理伺服器主機名』,填入127.0.0.1

選取『代理伺服器埠』,填入3128
正常便可通過官方客戶端連接推特
推特官方客戶端沒有測試,應大致相同,請自行摸索。
只有推特APP遠不足夠,但由於安卓支持設置HTTP代理的apps不多,這樣
有些網站須用瀏覽器訪問網站手機網頁版,在安卓開源市場已知有兩款可
以設置代理的瀏覽器

IceCatMobile + Proxy Mobile插件

安裝好icecatmobile,利用它打開Proxy Mobile插件網址安裝,點擊右上角的按鈕,
點選『工具』
然後選取『附加元件』
選取Proxy Mobile
填入正確的資料
這時可以訪問這個網站,看看IP是否改變了?
不過這個組合有時失靈,瀏覽器會不經代理接上網站,於是找了另一個代替

Lightning Browser

這個也是在安卓開源市場下載,它自帶代理設置,無須使用插件,按右上角
按鈕,找到"setting"
點選"General Setting"
點選『HTTP Proxy』
選擇『Manual』
填入資料
按OK,訪問網站測試一下是否使用代理
以上這些都可以使用大殺器客戶端上網,可能有更多apps能設置代理,就等網友
慢慢找尋了。
不過官方客戶端還是限制多,幸好推油@postern_overwal,他也是商業梯子供應商
開發了PosternAndroid下的系统全局代理Proxifier,這個是用VPN模式,不須要在
客戶端設置代理使用,可以使用規則匹配網址,或者全局代理。
安裝好客戶端後,打開Postern,點選配置代理
選取『大殺器GFW.Press(實驗性支持)』
填入服務器的資訊,保存後點選『配置規則』,這裡選單有四個選項
只測試了直連和通過代理連接的方式,現在使用規則,打開『通過代理連接』
裡面已有一些網址,可自行添加,減少便直接編輯
代理選回已設置好的大殺器,如上圖,編輯不要用中文輸入法去刪除或增加,用
系統自帶的英文輸入法,設置後保存,如用規則型式應是這樣
如果是使用全局的,設置好後是這樣,默認規則和通過代理都是『通過代理』
我因為測試,只在規則加了這個網站測試
然後全局測試,使用HKGolden這個不能設置代理的app連接網站
在VPS上監察是否通過服務器連接
正常連接,由於Postern只支援Connect方式,而Get未有支援,後端服務器必須配置
為可用CONNECT 方式才成,這看安裝的後端代理是那個。
另外建議設置DNS代理,不然會使用ISP的DNS,如圖
然後訪問一下這個網站,測試有沒有使用ISP的DNS服務器
這些測試非常簡陋,錯誤在所難免,另外因為無牆,不能測試它的智能DNS,據作
者說撞牆的網址會加入到代理規則,這得由網友測試了
最後感謝這些推友為抵抗資訊審查,做出各種工具做福人群,無私地分享,暫時iOS
上還未有可用的客戶端,不過相信很快出現了。
由於大殺器開始有點人氣,github上出現其他版本的GFW.Press,有興趣的網友自行
研究。
-----------
成功的用它来翻墙了,不过速度较慢。看不了youtube视频。
-------------

GFW.press源码简析

GFW.Press号称新一代军用级高强度加密抗干扰网络数据高速传输软件。作者@chinashiyu在twitter上很高调,该项目的代码简洁易懂,就像作者说的,人人开发翻墙工具的时代。
本篇剖析一下源码,示例代码为了可读性做了精简处理。

原理

  • 客户端监听本地端口,作为浏览器的HTTP代理的目标端口。对每一个连接请求,创建连接至服务器监听端口,建立起双向的数据转发。
  • 服务端监听端口,对每一个TCP连接请求,创建连接至HTTP代理服务器(通常安装在同一VPS上)监听端口,建立起双向的数据转发。
  • 其中客户端到服务端的TCP连接,数据是进行加密和随机字节填充了的。
  • 对于一个正常的HTTP代理,从浏览器到HTTP代理就一个TCP连接,然后在之上发送HTTP代理的数据包。对于GFW.press,从浏览器到GFW.press客户端一个TCP连接,从GFW.press客户端到GFW.press服务器一个数据加密的TCP连接,一个从GFW.press服务端到HTTP代理服务器的TCP连接。也就是说由原来1条TCP连接变成了3条TCP连接作为浏览器到HTTP代理的隧道。

Server

配置文件

目录下的user.txt即是配置文件,很简洁,就用户端口和密码,类似于shadowsocks的配置。
10006 ChangeMe1
10007 ChangeMe2
10008 ChangeMe3
还有server.json,配置HTTP代理
{  
    "ProxyHost": 127.0.0.1,
    "ProxyPort": 3128,
 }

端口监听

对每个用户端口,都开启一个新的服务线程(Server类实现)进行对该端口的端口监听,监听并处理用户连接
    # Server.java:Server.service():

    Enumeration<String> userPorts = users.keys();
    while (userPorts.hasMoreElements()) { // 新用户
            String userPort = userPorts.nextElement();
            Server thread = new Server(proxyHost, proxyPort, userPort, users.get(userPort));
            thread.start();
每个服务线程监听一个端口,为一个用户服务。线程对监听端口的每个连接,创建一个转发线程(ServerThread类实现),将一条连接的数据转发到代理上
    # Server.java:Server.run()
    # the listenPort is the userPort in user.txt config

    serverSocket = new ServerSocket(listenPort);
    while(True){
            clientSocket = serverSocket.accept();
            ServerThread serverThread = new ServerThread(clientSocket, proxyHost, proxyPort, key);
            serverThread.start();
    }
每个转发线程(ServerThread)完成一条从GFW.press客户端到GFW.press服务端、GFW.press服务到HTTP代理的TCP连接。转发线程创建一条连接至代理服务器,然后对客户端的连接进行读取数据、解密、转发解密后的明文数据到代理,然后对代理返回的数据,加密后返回给客户端。
    # ServerThread.java:ServerThread.run()

    // 连接代理服务器
    proxySocket = new Socket(proxyHost, proxyPort);

    // 获取输入输出流
    clientIn = clientSocket.getInputStream();
    clientOut = clientSocket.getOutputStream();

    proxyIn = proxySocket.getInputStream();
    proxyOut = proxySocket.getOutputStream();

    DecryptForwardThread forwardProxy = new DecryptForwardThread(clientIn, proxyOut, key);
    forwardProxy.start();

    EncryptForwardThread forwardClient = new EncryptForwardThread(proxyIn, clientOut, key);
    forwardClient.start();
如上,转发线程又开了两个线程,以分别处理上行转发流和下行转发流

Client

Windows.java实现了一个UI界面。最终会创建一个本地服务线程,并监听本地端口作为浏览器的HTTP代理目标端口。最终调用的代码如下
client = new Client(serverHost, serverPort, password, proxyPort);
client.start();
Client线程,创建本地监听端口,接受每一个TCP连接,并创建到服务器的转发线程(ClientThread)。
    # Client.java:Client.run()
    listenSocket = new ServerSocket(proxyPort);
    while(true){
        agentSocket = listenSocket.accept();
        ClientThread clientThread = new ClientThread(agentSocket, serverHost, serverPort, key);
        clientThread.start();
    }
客户端的转发线程(ClientThread)跟服务端的转发线程(ServerThread)都差不多,唯一不一样的就是上行流是先加密后转发,下行流是先解密后转发。而服务端的转发线程恰好相反,上行流是先解密后转发,下行流是先加密后转发。客户端的转发线程的转发目标是服务端的监听端口,而服务端的转发线程是HTTP代理服务器。
    # ClientThread.java:ClientThread.run()
    serverSocket = new Socket(serverHost, serverPort);
    // 获取输入输出流
    agentIn = agentSocket.getInputStream();
    agentOut = agentSocket.getOutputStream();
    serverIn = serverSocket.getInputStream();
    serverOut = serverSocket.getOutputStream();

    EncryptForwardThread forwardServer = new EncryptForwardThread(this, agentIn, serverOut, key);
    forwardServer.start();

    DecryptForwardThread forwardAgent = new DecryptForwardThread(this, serverIn, agentOut, key);
    forwardAgent.start();

转发数据流的加密

代码在Encrypt.java:encrypNet(),对每一块data,使用随机IV(16位)和key(password通过算法生成的16位key)加密,生成随机长度的噪音数据。加密后的数据长度/噪音数据长度值填在前面的30字节
+-----+----+--------+--------------+-------------+
|IV1  |size|  IV2   |   data       | noise bytes | 
+-----+----+--------+--------------+-------------+
| 16  | 14 |   16   |      1+      |     0+      | 
+-----+----+--------+--------------+-------------+
size是用IV1和key加密的,data是用IV2和key加密的。噪音随机字节是当data小于2K时会填充0–4K的字节,否则噪音数据是0字节。
public static final int NOISE_MAX = 1024 * 4; // 噪音数据最大长度,4K

byte[] noise_bytes = (cipher_bytes.length < NOISE_MAX / 2) ? getSecureRandom(secureRandom.nextInt(NOISE_MAX)) : new byte[0];
size那14个字节的存储格式如下,是把长度值写成字符串,而不是用整数值直接存储的。
String.format("%08d,%05d", data_size, noise_size).getBytes(CHARSET);
from https://medium.com/@FWTO_O/gfw-press%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90-61a2714eb99f#.1txkv7mzp