使用golang快速搭建socks5代理 2023/08/15

理论上,你可以使用Golang标准库(net包)来实现一个简单的SOCKS5服务器。简单的示例代码,演示如何使用Golang标准库创建一个SOCKS5服务器。

package main

import (
	"fmt"
	"net"
	"io"
)

func handleRequest(conn net.Conn) {
	// 读取版本和方法
	buffer := make([]byte, 2)
	_, err := conn.Read(buffer)
	if err != nil {
		fmt.Println("Failed to read version and method:", err)
		conn.Close()
		return
	}

	// 检查版本和方法是否为SOCKS5,并且方法数量大于0
	if buffer[0] != 5 || int(buffer[1]) <= 0 {
		fmt.Println("Invalid SOCKS version or method count")
		conn.Close()
		return
	}

	// 读取支持的认证方法
	authMethods := make([]byte, buffer[1])
	_, err = conn.Read(authMethods)
	if err != nil {
		fmt.Println("Failed to read authentication methods:", err)
		conn.Close()
		return
	}

	// 回复客户端,选择不需要认证
	conn.Write([]byte{5, 0})

	// 读取客户端请求
	_, err = conn.Read(buffer[:2])
	if err != nil {
		fmt.Println("Failed to read request version and command:", err)
		conn.Close()
		return
	}

	// 检查请求版本和命令是否为SOCKS5,并且RSV字段是否为0
	if buffer[0] != 5 || buffer[1] != 1 {
		fmt.Println("Invalid request version or command")
		conn.Close()
		return
	}

	// 读取目标地址类型
	_, err = conn.Read(buffer[:1])
	if err != nil {
		fmt.Println("Failed to read address type:", err)
		conn.Close()
		return
	}

	var host string
	switch buffer[0] {
	case 1: // IPv4地址
		addr := make([]byte, 4)
		_, err := conn.Read(addr)
		if err != nil {
			fmt.Println("Failed to read IPv4 address:", err)
			conn.Close()
			return
		}
		host = fmt.Sprintf("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3])

	case 3: // 域名
		_, err := conn.Read(buffer[:1])
		if err != nil {
			fmt.Println("Failed to read domain length:", err)
			conn.Close()
			return
		}
		domainLength := int(buffer[0])

		domainBytes := make([]byte, domainLength)
		_, err = conn.Read(domainBytes)
		if err != nil {
			fmt.Println("Failed to read domain:", err)
			conn.Close()
			return
		}
		host = string(domainBytes)

	case 4: // IPv6地址
		ipv6Addr := make([]byte, 16)
		_, err := conn.Read(ipv6Addr)
		if err != nil {
			fmt.Println("Failed to read IPv6 address:", err)
			conn.Close()
			return
		}
		host = net.IP(ipv6Addr).String()

	default:
		fmt.Println("Unsupported address type")
		conn.Close()
		return
	}

	// 读取目标端口
	portBuffer := make([]byte, 2)
	_, err = conn.Read(portBuffer)
	if err != nil {
		fmt.Println("Failed to read port:", err)
		conn.Close()
		return
	}
	port := int(portBuffer[0])<<8 + int(portBuffer[1])

	// 响应客户端,表示连接建立成功
	conn.Write([]byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0})

	// 连接目标服务器
	targetAddr := fmt.Sprintf("%s:%d", host, port)
	targetConn, err := net.Dial("tcp", targetAddr)
	if err != nil {
		fmt.Println("Failed to connect to target:", err)
		conn.Close()
		return
	}
	defer targetConn.Close()

	// 开始进行转发
	go io.Copy(targetConn, conn)
	io.Copy(conn, targetConn)
}

func main() {
	listener, err := net.Listen("tcp", "127.0.0.1:1080")
	if err != nil {
		fmt.Println("Failed to start SOCKS5 server:", err)
		return
	}
	defer listener.Close()

	fmt.Println("SOCKS5 server listening on 127.0.0.1:1080")

	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("Failed to accept connection:", err)
			continue
		}

		go handleRequest(conn)
	}
}

请注意,这只是一个简单的示例,可能需要根据你的实际需求进行修改和改进。此示例假设你的SOCKS5服务器不需要身份验证,并且只支持CONNECT命令。在实际的应用中,你可能需要根据需要进行身份验证,并支持其他命令。