什么是socks5代理
SOCKS5代理,又称为SOCKS5代理,是一种在使用TCP/IP协议的客户端和服务器之间传输流量的代理服务器。它的工作原理是SOCKS5代理服务器在客户端和真正的目标服务器之间扮演中介角色,通过转发请求和响应来实现通信。SOCKS5代理工作在会话层,对请求数据包本身不加任何改变。
socks5代理有什么好处
- 安全性:使用加密的连接,可以有效防止数据被窃取或被篡改。
- 灵活性:支持多种数据传输模式,满足各种网络需求。
- 匿名性:隐藏用户的真实IP地址,保护用户隐私。
SOCKS5代理还可以代理多种网络服务,如HTTP、SMTP、POP3和FTP等,广泛应用于网络安全、数据传输等领域。
SOCKS5代理服务端实现原理
-
连接建立:
- 当客户端想要访问某个网络服务时,它首先会向SOCKS5代理服务器发起连接请求。
- 代理服务器接收到请求后,会与客户端建立一个TCP连接。
-
认证过程:
- 在建立连接后,SOCKS5代理服务器可能会要求客户端进行认证。这通常包括用户名和密码的验证,或者基于其他认证机制。
- 如果认证成功,代理服务器会继续处理客户端的请求;如果认证失败,连接可能会被终止。
-
请求转发:
- 一旦认证通过,客户端会向代理服务器发送一个包含目标服务器地址和端口的请求。
- 代理服务器接收到这个请求后,会代表客户端与目标服务器建立连接。
-
数据传输:
- 代理服务器在客户端和目标服务器之间充当数据传输的中介。
- 它会将从客户端接收到的数据转发给目标服务器,并将从目标服务器接收到的响应数据转发给客户端。
-
连接管理:
- SOCKS5代理服务器需要管理多个客户端和目标服务器之间的连接。
- 这包括建立连接、维持连接、监控连接状态以及在必要时关闭连接。
SOCKS5代理服务端实现
创建服务端监听指定端口
这里直接用的:1080,使用127.0.0.1:1080会导致服务不对外开放,使用内网IP + 端口通用性较差,不建议使用。
func main() {
server, err := net.Listen("tcp", ":1080")
if err != nil {
panic(err)
}
for {
client, err := server.Accept()
if err != nil {
log.Printf("Accept failed %v", err)
continue
}
go process(client)
}
}
实现服务过程
服务分为两个部分,一个是协商过程,一个连接与数据转发实现。
func process(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
err := auth(reader, conn)
if err != nil {
log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
return
}
err = connect(reader, conn)
if err != nil {
log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
return
}
}
实现协商过程
协商方式我们能采用,无验证方法。接收客户端请求,然后根据方法组返回无验证方法或无可用方法即可。
func auth(reader *bufio.Reader, conn net.Conn) (err error) {
ver, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read ver failed:%w", err)
}
if ver != socks5Ver {
return fmt.Errorf("not supported ver:%v", ver)
}
methodSize, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read methodSize failed:%w", err)
}
method := make([]byte, methodSize)
_, err = io.ReadFull(reader, method)
if err != nil {
return fmt.Errorf("read method failed:%w", err)
}
_, err = conn.Write([]byte{socks5Ver, 0x00})
if err != nil {
return fmt.Errorf("write failed:%w", err)
}
return nil
}
实现连接与数据转发
协商完成后,我们将建立与目标服务器的连接。搭建好双向连接后,我们就可以直接将客户端发来的数据直接转发给目标服务端即可。
func connect(reader *bufio.Reader, conn net.Conn) (err error) {
buf := make([]byte, 4)
_, err = io.ReadFull(reader, buf)
if err != nil {
return fmt.Errorf("read header failed:%w", err)
}
ver, cmd, atyp := buf[0], buf[1], buf[3]
if ver != socks5Ver {
return fmt.Errorf("not supported ver:%v", ver)
}
if cmd != cmdBind {
return fmt.Errorf("not supported cmd:%v", cmd)
}
addr := ""
switch atyp {
case atypeIPV4:
_, err = io.ReadFull(reader, buf)
if err != nil {
return fmt.Errorf("read atyp failed:%w", err)
}
addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
case atypeHOST:
hostSize, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read hostSize failed:%w", err)
}
host := make([]byte, hostSize)
_, err = io.ReadFull(reader, host)
if err != nil {
return fmt.Errorf("read host failed:%w", err)
}
addr = string(host)
case atypeIPV6:
return errors.New("IPv6: no supported yet")
default:
return errors.New("invalid atyp")
}
_, err = io.ReadFull(reader, buf[:2])
if err != nil {
return fmt.Errorf("read port failed:%w", err)
}
port := binary.BigEndian.Uint16(buf[:2])
dest, err := net.Dial("tcp", fmt.Sprintf("%v:%v", addr, port))
if err != nil {
return fmt.Errorf("dial dst failed:%w", err)
}
defer dest.Close()
log.Println("dial", addr, port)
_, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
if err != nil {
return fmt.Errorf("write failed: %w", err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
_, _ = io.Copy(dest, reader)
cancel()
}()
go func() {
_, _ = io.Copy(conn, dest)
cancel()
}()
<-ctx.Done()
return nil
}
SOCKS5代理服务端部署
将编写的代码上传至服务端编译后并运行,如下图:
在浏览器中,通过SwitchyOmega插件设置代理为指定服务器外网IP和端口,成功进行代理服务,如下图: