VPS上嗨皮的跑了那么久shadowsock的server了, 但一直比较想搞明白具体是怎么实现的. 前段时间比较忙, 最近总算有点私人时间了, 速度的强读一发shadowsocks源码
G * F * W
有关就好了 所读源码基于 shadowsocks-go 1.1.5 , 为什么选择golang实现版本? 我难道会告诉你, Golang的吉祥物太萌了, 我已经决定好好安利golang了. 正经点的回复, golang的语法灵活不失简洁, 棒棒哒.
先来张图, 假装自己很专业…
目标的地址和端口
) aes-256-cfb
口说无凭, 也让人觉得云里雾里, 所以来是直接上代码吧
// local的入口 funcmain() { /* * 1. 设置日志配置和命令行参数解析 * 2. 从文件中读取相关配置, 如server ip, port, 用户设置的密码, 本地监控端口等 */ run(cmdLocal + ":"+ strconv.Itoa(config.LocalPort)) } // 实际监控函数 funcrun(listenAddrstring) { /* * 1. 设置要监控的端口 * 2. 在一个死循环中, 不断接收请求, 然后在goroutine中调用handleConnection(conn)处理请求 */ ln, err := net.Listen("tcp", listenAddr) for{// 运行与一个死循环 conn, err := ln.Accept() gohandleConnection(conn) } } // 运行在goroutine中请求处理函数 funchandleConnection(conn net.Conn) { /* * 1. 与请求进程进行心跳检测 * 2. 解析请求获取原始数据, 用于获取实际请求ip和port * 3. 与墙外的server请求建立TCP连接, 并发送数据 * 4. 等待墙外server写入数据, 然后将数据写回给请求进程 */ handShake(conn) rawaddr, addr, err := getRequest(conn) _, err = conn.Write([]byte{0x05,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x08,0x43}) remote, err := createServerConn(rawaddr, addr) goss.PipeThenClose(conn, remote) ss.PipeThenClose(remote, conn) }
最后我们来看一下 PipeThenClose
这个函数的实现
// PipeThenClose copies data from src to dst, closes dst when done. funcPipeThenClose(src, dst net.Conn) { // closes dst when done. deferdst.Close() /* * 1. 从leaky buffer中获取空闲buffer * 2. 从source net.Conn中读取数据, 然后转发给dst net.Conn */ buf := leakyBuf.Get() deferleakyBuf.Put(buf) for{ SetReadTimeout(src) n, err := src.Read(buf) // read may return EOF with n > 0 // should always process n > 0 bytes before handling error ifn >0{ // Note: avoid overwrite err returned by Read. if_, err := dst.Write(buf[0:n]); err !=nil{ Debug.Println("write:", err) break } } iferr !=nil{ break } } }
// 主要来handleConnection // goroutine, 内部需要自行保证线程安全 funchandleConnection(conn *ss.Conn, authbool) { /* * 1. 解析请求的ip:port * 2. 建立TCP连接 * 3. 向目标站点发起请求, 响应数据写会到local */ host, ota, err := getRequest(conn, auth) //对应ip:port建立TCP连接 remote, err := net.Dial("tcp", host) ifota { goss.PipeThenCloseOta(conn, remote) } else{ goss.PipeThenClose(conn, remote) } // 从remote读取数据 ss.PipeThenClose(remote, conn) closed = true return }
由local和server端总共四个 PipeThenClose
函数完成了由local到server, 再由server到local的数据传输. 但是要注意的是在 server端是没有与local进行心跳检测的阶段
socks v5代码TCP协议的流程:
VER, NMETHODS, METHODS
, 监听进程向请求进程响应 VER, METHOD
向监听进程的请求: +----+-----+-------+------+----------+----------+ |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | +----+-----+-------+------+----------+----------+ | 1|1| X'00'|1| Variable |2| +----+-----+-------+------+----------+----------+ 监听进程的响应: +----+-----+-------+------+----------+----------+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | +----+-----+-------+------+----------+----------+ | 1|1| X'00'|1| Variable |2| +----+-----+-------+------+----------+----------+ // 对应shadowsocks-local中的: _, err = conn.Write([]byte{0x05,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x08,0x43})