用go语言来实现socks5代理服务器,后面会加入ssh远程代理,用户验证,均衡负载一些吧
首先监听8080端口,循环接收tcp连接
server, err := net.Listen("tcp", ":8080")
if err != nil {
log.Panic(err)
}
defer server.Close()
log.Println("开始接受连接")
for {
client, err := server.Accept()
if err != nil {
log.Println(err)
return
}
log.Println("一个新连接")
go socks5Proxy(client)
}
socks5Proxy函数用来实现sock5代理
先介绍一下sock5代理协议
client:0x05 0x02 0x00 0x02 或 0x05 0x01 0x00 (主要是用户验证方面,咱们忽略,直接返回0x05 0x00)
server:0x05 0x00
client:0x05 0x01 0x00 0x01 ... 或 0x05 0x01 0x00 0x03 ... (0x01后面跟的是ip+port ,0x02是ip6+port, 0x03跟的是domainName+port,因为是二进制,要用到binary包解码,然后就可以直接用net.Dial进行连接,go会自动转换到域名到ip,所以可以直接用)
server:0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 (当服务端确定能进行代理返回确定)
然后就是两个io.Copy来进行代理转发就行了,下面是代码
func socks5Proxy(conn net.Conn) {
defer conn.Close()
var b [1024]byte
n, err := conn.Read(b[:])
if err != nil {
log.Println(err)
return
}
log.Printf("% x", b[:n])
conn.Write([]byte{0x05, 0x00})
n, err = conn.Read(b[:])
if err != nil {
log.Println(err)
return
}
log.Printf("% x", b[:n])
var addr string
switch b[3] {
case 0x01:
sip := sockIP{}
if err := binary.Read(bytes.NewReader(b[4:n]), binary.BigEndian, &sip); err != nil {
log.Println("请求解析错误")
return
}
addr = sip.toAddr()
case 0x03:
host := string(b[5 : n-2])
var port uint16
err = binary.Read(bytes.NewReader(b[n-2:n]), binary.BigEndian, &port)
if err != nil {
log.Println(err)
return
}
addr = fmt.Sprintf("%s:%d", host, port)
}
server, err := net.Dial("tcp", addr)
if err != nil {
log.Println(err)
return
}
conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
go io.Copy(server, conn)
io.Copy(conn, server)
}