以后,所有目标是80端口的TCP数据包都会转发给该程序(这里的程序,因为使用的是Socket编程接口,所以首先由Socket层来处理)。所谓accept函数,其实抽象的是TCP的连接建立过程。accept函数返回的新socket其实指代的是本次创建的连接,而一个连接是包括两部分信息的,一个是源IP和源端口,另一个是宿IP和宿端口。
1.客户端连接到代理服务器开放的端口;2.客户端向代理服务器发送验证申请;
3.代理服务器向客户端发送一个数据包,从而客户端得知自己的通信申请是否被批准;
4.客户端向代理服务器发送一个数据包,告知代理服务器自己要连接的目的主机的地址和端口;
5.代理服务器开始进行到目的主机的真正连接;
6.代理服务器为客户端开放一个新的端口并向客户端发送一个数据包告知客户端这个新的端口;
7.客户端创建一个新的套接字并连接到代理服务器的新的端口;
8.然后,代理服务器把由新端口接收到的数据都转发给目的主机,把从目的主机发过来的数据都由新端口转发给客户端。
代理服务器解析客户端传入的数据,得到服务器ip和端口,然后创建与服务器的连接。解析代码如下:(这里只处理了socket v5的情况,Config的常量对应java.net.SocksConsts)
try {// socket v5
// 4byte(5 2 0 2) @see java.net.SocksSocketImpl
int len = dis.read(buffer)
// reply client
dos.write(new byte[]{Config.PROTO_VERS, Config.NO_AUTH})
dos.flush()
// read
// PROTO_VERS(1byte)
// CONNECT(1byte)
// 0(1byte)
// DOMAIN_NAME/IPV4/IPV6(1byte) DOMAIN_NAME(not consider now)
// addr(IPV4:4byte/IPV6:16byte)
// port>>8&0xff(1byte)
// port&0xff(1byte)
len = dis.read(buffer)
byte addrType = buffer[3]
byte[] applyData = null
String serverIp = null
int serverPort = 0
if (addrType == Config.IPV4) {
serverIp = Util.bytes2ipv4(buffer, 4, 4)
serverPort = buffer[8] << 8 | buffer[9]
// set reply data
applyData = new byte[10]
applyData[1] = Config.REQUEST_OK
applyData[3] = Config.IPV4
for (int i = 4 i < 10 i++) {
// fill ip, port
applyData[i] = buffer[i]
}
} else if (addrType == Config.IPV6) {
serverIp = Util.bytes2ipv6(buffer, 4, 16)
serverPort = buffer[20] << 8 | buffer[21]
// set reply data
applyData = new byte[6]
applyData[1] = Config.REQUEST_OK
applyData[3] = Config.IPV6
applyData[4] = buffer[20]
applyData[5] = buffer[21]
}
// reply
dos.write(applyData)
dos.flush()
// connect the server
// serverIp是服务器ip,serverPort是服务器端口,用这两个
// 创建与服务器的socket连接
Socket socket = new Socket(serverIp, serverPort)
// 之后处理客户端与服务器的数据交互就用这个socket转发就行了
// finally success!!!
} catch (Exception e) {
e.printStackTrace()
}
欢迎分享,转载请注明来源:夏雨云
评论列表(0条)