-----server.go-----

package main

import (
    "bufio"
    "bytes"
    "encoding/base64"
    "encoding/binary"
    "errors"
    "fmt"
    "io"
    "net"
    "net/http"
    "strconv"
    "strings"
    "sync"
    "time"
)

const (
    clientPort = 10102 // Client connection port
    proxyPort  = 10101 // Proxy server port
    password   = "123456"
    udpTimeout = 60 * time.Second
)

var (
    // Map to store client ID to Client struct
    clientConnMap = make(map[string]*Client)
    connMutex     sync.RWMutex
)

type Client struct {
    id         string
    conn       net.Conn
    connChan   chan ProxyRequest
    udpChan    chan UDPRequest
    disconnect chan struct{}
}

type ProxyRequest struct {
    conn        net.Conn
    targetAddr  string
    initialData []byte // Initial HTTP request data
}

type UDPRequest struct {
    remoteAddr *net.UDPAddr
    data       []byte
}

func main() {
    // Start client connection listener
    go startClientListener()


Copy code
// Start proxy service listener
startProxyListener()
}

// Start listening for client connections
func startClientListener() {
    listener, err := net.Listen("tcp", ":"+strconv.Itoa(clientPort))
    if err != nil {
        fmt.Println("Failed to start client listener:", err)
        return
    }
    fmt.Println("Client connection listener started on port:", clientPort)
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("Failed to accept client connection:", err)
            continue
        }
        go handleClientConn(conn)
    }
}

// Handle incoming client connections
func handleClientConn(conn net.Conn) {
    reader := bufio.NewReader(conn)
    // Read client ID
    id, err := reader.ReadString('\n')
    if err != nil {
        fmt.Println("Failed to read client ID:", err)
        conn.Close()
        return
    }
    id = strings.TrimSpace(id)
    if id == "" {
        fmt.Println("Client ID cannot be empty")
        conn.Close()
        return
    }


Copy code
client := &Client{
    id:         id,
    conn:       conn,
    connChan:   make(chan ProxyRequest, 100), // Buffered channel to prevent blocking
    udpChan:    make(chan UDPRequest, 100),
    disconnect: make(chan struct{}),
}

// Store client connection
connMutex.Lock()
clientConnMap[id] = client
connMutex.Unlock()
fmt.Printf("Client [%s] connected\n", id)

go clientHandle(client)
}

// Handle client communication
func clientHandle(client *Client) {
    defer func() {
        // Clean up on client disconnect
        connMutex.Lock()
        delete(clientConnMap, client.id)
        connMutex.Unlock()
        client.conn.Close()
        close(client.disconnect)
        fmt.Printf("Client [%s] disconnected\n", client.id)
    }()


Copy code
// Start UDP handler
go handleUDP(client)

for {
    select {
    case pr := <-client.connChan:
        // Notify client to establish a new TCP connection
        fmt.Fprintln(client.conn, "NEW_CONN")
        // Send target address to client
        fmt.Fprintf(client.conn, "TARGET %s\n", pr.targetAddr)
        // Send local listening port to client
        localListener, err := net.Listen("tcp", ":0")
        if err != nil {
            fmt.Println("Failed to listen on local port:", err)
            pr.conn.Close()
            continue
        }
        port := localListener.Addr().(*net.TCPAddr).Port
        fmt.Fprintf(client.conn, "PORT %d\n", port)
        fmt.Printf("Waiting for client to connect on port %d\n", port)
        // Accept client connection
        clientConn, err := localListener.Accept()
        localListener.Close()
        if err != nil {
            fmt.Println("Failed to accept client connection on port:", err)
            pr.conn.Close()
            continue
        }
        fmt.Printf("Client connected on port %d\n", port)
        // If there is initial data, send it first
        if len(pr.initialData) > 0 {
            _, err := clientConn.Write(pr.initialData)
            if err != nil {
                fmt.Println("Failed to send initial data:", err)
                clientConn.Close()
                pr.conn.Close()
                continue
            }
        }
        // Start bidirectional data transfer
        go transferData(pr.conn, clientConn)
    case udpReq := <-client.udpChan:
        // Handle UDP requests
        handleUDPRelay(client, udpReq)
    case <-client.disconnect:
        return
    }
}
}

// Handle UDP forwarding for a client
func handleUDP(client *Client) {
    for {
        select {
        case udpReq := <-client.udpChan:
            // Forward UDP data to the target via the client
            go forwardUDP(client, udpReq)
        case <-client.disconnect:
            return
        }
    }
}

// Forward UDP data to the target via the client
func forwardUDP(client *Client, udpReq UDPRequest) {
    // Here, you can implement the logic to forward UDP data to the client.
    // This could involve sending the data over the existing TCP connection
    // or establishing a separate UDP connection.


Copy code
// For simplicity, we'll assume that the client can handle UDP forwarding
// and that you have a mechanism to send UDP data to the client.
// This part needs to be implemented based on your specific requirements.

// Example: Send UDP data to the client (pseudo-code)
// err := sendToClient(client, udpReq.remoteAddr, udpReq.data)
// if err != nil {
//     fmt.Println("Failed to send UDP data to client:", err)
// }

// Placeholder implementation
fmt.Printf("Forwarding UDP data to client [%s]: %s\n", client.id, string(udpReq.data))
// Implement actual forwarding logic here
}

// Transfer data between two TCP connections
func transferData(conn1, conn2 net.Conn) {
    defer conn1.Close()
    defer conn2.Close()
    done := make(chan struct{}, 2)


Copy code
go func() {
    _, err := io.Copy(conn1, conn2)
    if err != nil && !isClosedNetworkError(err) {
        fmt.Println("Data transfer error:", err)
    }
    done <- struct{}{}
}()
go func() {
    _, err := io.Copy(conn2, conn1)
    if err != nil && !isClosedNetworkError(err) {
        fmt.Println("Data transfer error:", err)
    }
    done <- struct{}{}
}()
<-done
}

// Check if the error is "use of closed network connection"
func isClosedNetworkError(err error) bool {
    if err == nil {
        return false
    }
    return strings.Contains(err.Error(), "use of closed network connection")
}

// Start listening for proxy connections
func startProxyListener() {
    listener, err := net.Listen("tcp", ":"+strconv.Itoa(proxyPort))
    if err != nil {
        fmt.Println("Failed to start proxy listener:", err)
        return
    }
    fmt.Println("Proxy service listener started on port:", proxyPort)
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("Failed to accept proxy connection:", err)
            continue
        }
        go handleProxyConn(conn)
    }
}

// Handle incoming proxy connections
func handleProxyConn(conn net.Conn) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from panic while handling proxy connection:", r)
            conn.Close()
        }
    }()


Copy code
// Read first two bytes to determine if it's HTTP or SOCKS5
conn.SetReadDeadline(time.Now().Add(2 * time.Second))
buffer := make([]byte, 2)
n, err := conn.Read(buffer)
if err != nil || n != 2 {
    fmt.Println("Failed to read initial bytes:", err)
    conn.Close()
    return
}
conn.SetReadDeadline(time.Time{}) // Remove deadline

if buffer[0] == 0x05 {
    // SOCKS5 proxy
    handleSocks5Proxy(conn, buffer[:n])
} else {
    // HTTP proxy
    handleHTTPProxy(conn, buffer[:n])
}
}

// Handle HTTP proxy connections
func handleHTTPProxy(conn net.Conn, firstBytes []byte) {
    // Read the full HTTP request
    reader := bufio.NewReader(io.MultiReader(bytes.NewReader(firstBytes), conn))
    req, err := http.ReadRequest(reader)
    if err != nil {
        conn.Close()
        fmt.Println("Failed to read HTTP request:", err)
        return
    }


Copy code
// Parse Proxy-Authorization header
username, pwd, ok := parseBasicAuth(req.Header.Get("Proxy-Authorization"))
if !ok || pwd != password {
    conn.Write([]byte("HTTP/1.1 407 Proxy Authentication Required\r\nProxy-Authenticate: Basic realm=\"proxy\"\r\n\r\n"))
    conn.Close()
    return
}

// Find corresponding client
client := getClient(username)
if client == nil {
    conn.Write([]byte("HTTP/1.1 503 Service Unavailable\r\n\r\n"))
    conn.Close()
    return
}

var targetAddr string
var initialData []byte

if req.Method == "CONNECT" {
    targetAddr = req.Host
    if !strings.Contains(targetAddr, ":") {
        targetAddr += ":443"
    }
    // HTTPS proxy
    _, err = conn.Write([]byte("HTTP/1.1 200 Connection Established\r\n\r\n"))
    if err != nil {
        fmt.Println("Failed to send connection established response:", err)
        conn.Close()
        return
    }
} else {
    // HTTP proxy
    targetAddr = req.URL.Host
    if targetAddr == "" {
        targetAddr = req.Host
    }
    if !strings.Contains(targetAddr, ":") {
        targetAddr += ":80"
    }
    // Re-serialize HTTP request
    var buf bytes.Buffer
    err = req.Write(&buf)
    if err != nil {
        fmt.Println("Failed to serialize HTTP request:", err)
        conn.Write([]byte("HTTP/1.1 500 Internal Server Error\r\n\r\n"))
        conn.Close()
        return
    }
    initialData = buf.Bytes()
}

// Create ProxyRequest
pr := ProxyRequest{
    conn:        conn,
    targetAddr:  targetAddr,
    initialData: initialData,
}

// Forward ProxyRequest to client
select {
case client.connChan <- pr:
    fmt.Printf("HTTP proxy request forwarded to client [%s], target: %s\n", client.id, targetAddr)
default:
    // Cannot handle new connection
    if req.Method == "CONNECT" {
        conn.Write([]byte("HTTP/1.1 503 Service Unavailable\r\n\r\n"))
    } else {
        conn.Write([]byte("HTTP/1.1 503 Service Unavailable\r\n\r\n"))
    }
    conn.Close()
    return
}
}

// Handle SOCKS5 proxy connections
func handleSocks5Proxy(conn net.Conn, firstBytes []byte) {
    reader := bufio.NewReader(io.MultiReader(bytes.NewReader(firstBytes), conn))
    // Authentication phase
    username, err := socks5Auth(conn, reader)
    if err != nil {
        fmt.Println("SOCKS5 authentication failed:", err)
        conn.Close()
        return
    }
    // Find corresponding client
    client := getClient(username)
    if client == nil {
        // Cannot find corresponding client
        conn.Write([]byte{0x05, 0xFF}) // Server failure
        conn.Close()
        return
    }
    // Request phase
    err = socks5Request(conn, reader, client)
    if err != nil {
        fmt.Println("Failed to handle SOCKS5 request:", err)
        conn.Close()
        return
    }
}

// SOCKS5 authentication
func socks5Auth(conn net.Conn, reader *bufio.Reader) (string, error) {
    // Read VER, NMETHODS
    header := make([]byte, 2)
    _, err := io.ReadFull(reader, header)
    if err != nil {
        return "", err
    }
    ver := header[0]
    nmethods := int(header[1])


Copy code
if ver != 0x05 {
    return "", errors.New("unsupported SOCKS version")
}

methods := make([]byte, nmethods)
_, err = io.ReadFull(reader, methods)
if err != nil {
    return "", err
}

fmt.Printf("Received SOCKS5 methods: %v\n", methods)

// Check if username/password authentication is supported (0x02)
var supportUserPass bool
for _, method := range methods {
    if method == 0x02 {
        supportUserPass = true
        break
    }
}

if !supportUserPass {
    // No acceptable methods
    conn.Write([]byte{0x05, 0xFF})
    return "", errors.New("no supported authentication methods")
}

// Server selects username/password authentication
conn.Write([]byte{0x05, 0x02})

// Handle username/password authentication
version, err := reader.ReadByte()
if err != nil {
    return "", err
}
if version != 0x01 {
    return "", errors.New("unsupported authentication version")
}
unameLen, err := reader.ReadByte()
if err != nil {
    return "", err
}
uname := make([]byte, unameLen)
_, err = io.ReadFull(reader, uname)
if err != nil {
    return "", err
}
pwdLen, err := reader.ReadByte()
if err != nil {
    return "", err
}
pwd := make([]byte, pwdLen)
_, err = io.ReadFull(reader, pwd)
if err != nil {
    return "", err
}
// Validate username and password
if string(pwd) != password {
    // Authentication failed
    conn.Write([]byte{0x01, 0x01})
    return "", errors.New("invalid password")
}
// Authentication successful
conn.Write([]byte{0x01, 0x00})
return string(uname), nil
}

// Handle SOCKS5 requests
func socks5Request(conn net.Conn, reader *bufio.Reader, client *Client) error {
    // Read request: VER, CMD, RSV, ATYP
    header := make([]byte, 4)
    _, err := io.ReadFull(reader, header)
    if err != nil {
        return err
    }
    ver := header[0]
    cmd := header[1]
    atyp := header[3]


Copy code
if ver != 0x05 {
    return errors.New("unsupported SOCKS version in request")
}

// Read destination address
var destAddr string
switch atyp {
case 0x01:
    // IPv4
    ip := make([]byte, 4)
    _, err := io.ReadFull(reader, ip)
    if err != nil {
        return err
    }
    destAddr = net.IP(ip).String()
case 0x03:
    // Domain name
    var domainLen byte
    err := binary.Read(reader, binary.BigEndian, &domainLen)
    if err != nil {
        return err
    }
    domain := make([]byte, domainLen)
    _, err = io.ReadFull(reader, domain)
    if err != nil {
        return err
    }
    destAddr = string(domain)
case 0x04:
    // IPv6
    ip := make([]byte, 16)
    _, err := io.ReadFull(reader, ip)
    if err != nil {
        return err
    }
    destAddr = net.IP(ip).String()
default:
    return errors.New("unsupported ATYP in SOCKS5 request")
}

// Read destination port
var destPort uint16
err = binary.Read(reader, binary.BigEndian, &destPort)
if err != nil {
    return err
}

targetAddr := net.JoinHostPort(destAddr, strconv.Itoa(int(destPort)))

switch cmd {
case 0x01:
    // CONNECT command
    // Respond to client that the connection is established
    // Reply: VER, REP, RSV, ATYP, BND.ADDR, BND.PORT
    reply := []byte{0x05, 0x00, 0x00, 0x01} // VER, REP=success, RSV, ATYP=IPv4
    reply = append(reply, net.ParseIP("0.0.0.0").To4()...)
    reply = append(reply, []byte{0x00, 0x00}...) // BND.PORT
    _, err = conn.Write(reply)
    if err != nil {
        return err
    }

    // Create ProxyRequest
    pr := ProxyRequest{
        conn:        conn,
        targetAddr:  targetAddr,
        initialData: nil, // No initial data for SOCKS5 CONNECT
    }

    // Forward ProxyRequest to client
    select {
    case client.connChan <- pr:
        fmt.Printf("SOCKS5 CONNECT request forwarded to client [%s], target: %s\n", client.id, targetAddr)
    default:
        // Cannot handle new connection
        reply := []byte{0x05, 0x01, 0x00, 0x01} // REP=general failure
        reply = append(reply, net.ParseIP("0.0.0.0").To4()...)
        reply = append(reply, []byte{0x00, 0x00}...)
        conn.Write(reply)
        return errors.New("unable to forward connection to client")
    }
case 0x03:
    // UDP ASSOCIATE command
    // Allocate a UDP relay port
    udpListener, err := net.ListenUDP("udp", &net.UDPAddr{
        IP:   net.ParseIP("0.0.0.0"),
        Port: 0, // Let the system choose an available port
    })
    if err != nil {
        fmt.Println("Failed to allocate UDP relay port:", err)
        reply := []byte{0x05, 0x01, 0x00, 0x01} // REP=general failure
        reply = append(reply, net.ParseIP("0.0.0.0").To4()...)
        reply = append(reply, []byte{0x00, 0x00}...)
        conn.Write(reply)
        return err
    }
    defer udpListener.Close()

    relayAddr := udpListener.LocalAddr().(*net.UDPAddr)
    fmt.Printf("Allocated UDP relay port %d for client [%s]\n", relayAddr.Port, client.id)

    // Get server's public IP address
    serverIP, err := getLocalIP()
    if err != nil {
        fmt.Println("Failed to get server IP:", err)
        reply := []byte{0x05, 0x01, 0x00, 0x01} // REP=general failure
        reply = append(reply, net.ParseIP("0.0.0.0").To4()...)
        reply = append(reply, []byte{0x00, 0x00}...)
        conn.Write(reply)
        return err
    }

    // Respond to client with the UDP relay address
    reply := []byte{0x05, 0x00, 0x00, 0x01} // VER, REP=success, RSV, ATYP=IPv4
    reply = append(reply, net.ParseIP(serverIP).To4()...)
    reply = append(reply, []byte{byte(relayAddr.Port >> 8), byte(relayAddr.Port & 0xFF)}...)
    _, err = conn.Write(reply)
    if err != nil {
        fmt.Println("Failed to send UDP ASSOCIATE reply:", err)
        return err
    }

    // Handle UDP relay
    go handleUDPRelayConnection(client, udpListener)
default:
    // Unsupported CMD
    reply := []byte{0x05, 0x07, 0x00, 0x01} // REP=command not supported
    reply = append(reply, net.ParseIP("0.0.0.0").To4()...)
    reply = append(reply, []byte{0x00, 0x00}...)
    conn.Write(reply)
    return errors.New("unsupported SOCKS5 command")
}
return nil
}

// Handle UDP relay connection
func handleUDPRelayConnection(client *Client, udpListener *net.UDPConn) {
    buffer := make([]byte, 65535)
    for {
        udpListener.SetReadDeadline(time.Now().Add(udpTimeout))
        n, addr, err := udpListener.ReadFromUDP(buffer)
        if err != nil {
            if ne, ok := err.(net.Error); ok && ne.Timeout() {
                // Timeout, continue to listen
                continue
            }
            fmt.Println("Error reading from UDP relay:", err)
            return
        }


Copy code
    // Parse SOCKS5 UDP request
    socks5Packet, err := parseSocks5UDPRequest(buffer[:n])
    if err != nil {
        fmt.Println("Failed to parse SOCKS5 UDP request:", err)
        continue
    }

    // Forward the UDP data to the client for relaying
    udpReq := UDPRequest{
        remoteAddr: addr,
        data:       socks5Packet.data,
    }

    select {
    case client.udpChan <- udpReq:
        fmt.Printf("UDP packet from %s to %s forwarded to client [%s]\n", addr.String(), socks5Packet.targetAddr, client.id)
        // Now, send the UDP data to the target address
        go forwardUDPToTarget(socks5Packet.targetAddr, socks5Packet.data, udpListener)
    default:
        fmt.Println("UDP channel is full, dropping packet")
    }
}
}

// Parse SOCKS5 UDP request
type Socks5UDPRequest struct {
    targetAddr string
    data       []byte
}

func parseSocks5UDPRequest(packet []byte) (*Socks5UDPRequest, error) {
    if len(packet) < 10 {
        return nil, errors.New("invalid UDP packet length")
    }
    reader := bytes.NewReader(packet)
    //cmd
    var ver, rsv, atyp byte
    err := binary.Read(reader, binary.BigEndian, &ver)
    if err != nil {
        return nil, err
    }
    err = binary.Read(reader, binary.BigEndian, &rsv)
    if err != nil {
        return nil, err
    }
    err = binary.Read(reader, binary.BigEndian, &atyp)
    if err != nil {
        return nil, err
    }


Copy code
var addr string
switch atyp {
case 0x01:
    // IPv4
    ip := make([]byte, 4)
    _, err := io.ReadFull(reader, ip)
    if err != nil {
        return nil, err
    }
    addr = net.IP(ip).String()
case 0x03:
    // Domain name
    var domainLen byte
    err := binary.Read(reader, binary.BigEndian, &domainLen)
    if err != nil {
        return nil, err
    }
    domain := make([]byte, domainLen)
    _, err = io.ReadFull(reader, domain)
    if err != nil {
        return nil, err
    }
    addr = string(domain)
case 0x04:
    // IPv6
    ip := make([]byte, 16)
    _, err := io.ReadFull(reader, ip)
    if err != nil {
        return nil, err
    }
    addr = net.IP(ip).String()
default:
    return nil, errors.New("unsupported ATYP in UDP packet")
}

// Read destination port
var destPort uint16
err = binary.Read(reader, binary.BigEndian, &destPort)
if err != nil {
    return nil, err
}

targetAddr := net.JoinHostPort(addr, strconv.Itoa(int(destPort)))

// Read the remaining data
payload, err := io.ReadAll(reader)
if err != nil {
    return nil, err
}

return &Socks5UDPRequest{
    targetAddr: targetAddr,
    data:       payload,
}, nil
}

// Forward UDP data to the target address
func forwardUDPToTarget(targetAddr string, data []byte, udpListener *net.UDPConn) {
    conn, err := net.Dial("udp", targetAddr)
    if err != nil {
        fmt.Println("Failed to dial UDP target:", err)
        return
    }
    defer conn.Close()


Copy code
_, err = conn.Write(data)
if err != nil {
    fmt.Println("Failed to send UDP data to target:", err)
    return
}

// Optionally, handle responses from the target
// This can be implemented as needed
}

// Handle UDP relay
func handleUDPRelay(client *Client, udpReq UDPRequest) {
    // Implement the logic to relay UDP data back to the client
    // This could involve wrapping the data in SOCKS5 UDP response format
    // and sending it to the UDP relay port associated with the client.


Copy code
// Placeholder implementation
fmt.Printf("Received UDP data from client [%s]: %s\n", client.id, string(udpReq.data))
// Implement actual relay logic here
}

// Get the local IP address of the server
func getLocalIP() (string, error) {
    // Attempt to find the non-loopback IP address
    conn, err := net.Dial("udp", "8.8.8.8:80")
    if err != nil {
        return "", err
    }
    defer conn.Close()
    localAddr := conn.LocalAddr().(*net.UDPAddr)
    return localAddr.IP.String(), nil
}

// Get a client by ID
func getClient(id string) *Client {
    connMutex.RLock()
    defer connMutex.RUnlock()
    return clientConnMap[id]
}

// Parse Basic Authentication header
func parseBasicAuth(auth string) (username, password string, ok bool) {
    const prefix = "Basic "
    if !strings.HasPrefix(auth, prefix) {
        return
    }
    payload := auth[len(prefix):]
    decoded, err := base64.StdEncoding.DecodeString(payload)
    if err != nil {
        return
    }
    pair := strings.SplitN(string(decoded), ":", 2)
    if len(pair) != 2 {
        return
    }
    return pair[0], pair[1], true
}

-----client.go---------------------------------------------------------------------------

package main

import (
    "bufio"
    "encoding/binary"
    "flag"
    "fmt"
    "io"
    "net"
    "os"
    "strconv"
    "strings"
    "sync"
    "time"
    "bytes"
    "errors"
)

var (
    clientID   string
    serverAddr string
    password   string
)

func main() {
    // Parse command-line arguments
    flag.StringVar(&serverAddr, "server", "", "Server address (e.g., 127.0.0.1:10102)")
    flag.StringVar(&clientID, "id", "", "Client ID")
    flag.StringVar(&password, "password", "123456", "Authentication password")
    flag.Parse()


Copy code
if clientID == "" || serverAddr == "" {
    fmt.Println("Usage: client -id= -server= -password=")
    os.Exit(1)
}

// Connect to the server
for {
    err := connectToServer()
    if err != nil {
        fmt.Println("Failed to connect to server:", err)
        time.Sleep(5 * time.Second) // Add delay to avoid rapid retries
    }
}
}

func connectToServer() error {
    conn, err := net.Dial("tcp", serverAddr)
    if err != nil {
        return err
    }
    defer conn.Close()
    // Send Client ID
    fmt.Fprintf(conn, "%s\n", clientID)
    fmt.Printf("Connected to server [%s]\n", serverAddr)


Copy code
reader := bufio.NewReader(conn)

var udpRelayAddr string
//var udpConn *net.UDPConn
var udpMutex sync.Mutex

for {
    line, err := reader.ReadString('\n')
    if err != nil {
        fmt.Println("Connection closed:", err)
        return err
    }
    line = strings.TrimSpace(line)
    if line == "NEW_CONN" {
        // Read target address
        targetLine, err := reader.ReadString('\n')
        if err != nil {
            fmt.Println("Failed to read target address:", err)
            continue
        }
        targetLine = strings.TrimSpace(targetLine)
        var targetAddr string
        if strings.HasPrefix(targetLine, "TARGET ") {
            targetAddr = strings.TrimPrefix(targetLine, "TARGET ")
        } else {
            fmt.Println("No target address received")
            continue
        }
        // Read port number
        portLine, err := reader.ReadString('\n')
        if err != nil {
            fmt.Println("Failed to read port number:", err)
            continue
        }
        portLine = strings.TrimSpace(portLine)
        if strings.HasPrefix(portLine, "PORT ") {
            portStr := strings.TrimPrefix(portLine, "PORT ")
            port, err := strconv.Atoi(portStr)
            if err != nil {
                fmt.Println("Failed to parse port number:", err)
                continue
            }
            go handleNewConn(port, targetAddr)
        }
    } else if strings.HasPrefix(line, "UDP_RELAY ") {
        // Handle UDP relay setup
        udpRelayAddr = strings.TrimPrefix(line, "UDP_RELAY ")
        fmt.Printf("UDP relay address: %s\n", udpRelayAddr)
        go setupUDPRelay(udpRelayAddr, &udpMutex)
    }
}
}

func handleNewConn(port int, targetAddr string) {
    // Establish new TCP connection to the assigned port on the server
    addr := serverAddr // Use the server address provided via command-line
    fullAddr := net.JoinHostPort(getHost(addr), strconv.Itoa(port))
    fmt.Printf("Attempting to connect to new server port: %s\n", fullAddr)
    clientConn, err := net.Dial("tcp", fullAddr)
    if err != nil {
        fmt.Println("Failed to establish new connection to server:", err)
        return
    }
    fmt.Printf("Successfully connected to new server port: %s\n", fullAddr)


Copy code
// Establish connection to the target server
targetConn, err := net.Dial("tcp", targetAddr)
if err != nil {
    fmt.Println("Failed to connect to target address:", err)
    clientConn.Close()
    return
}
fmt.Printf("Successfully connected to target address: %s\n", targetAddr)

// Start bidirectional data transfer
var wg sync.WaitGroup
wg.Add(2)

go func() {
    defer wg.Done()
    _, err := io.Copy(targetConn, clientConn)
    if err != nil && !isClosedNetworkError(err) {
        fmt.Println("Data transfer error:", err)
    }
}()

go func() {
    defer wg.Done()
    _, err := io.Copy(clientConn, targetConn)
    if err != nil && !isClosedNetworkError(err) {
        fmt.Println("Data transfer error:", err)
    }
}()

wg.Wait()
clientConn.Close()
targetConn.Close()
fmt.Printf("Data transfer ended: %s <--> %s\n", targetAddr, fullAddr)
}

// Setup UDP relay
func setupUDPRelay(relayAddr string, udpMutex *sync.Mutex) {
    udpAddr, err := net.ResolveUDPAddr("udp", relayAddr)
    if err != nil {
        fmt.Println("Failed to resolve UDP relay address:", err)
        return
    }


Copy code
// Establish UDP connection to the server's UDP relay
udpConn, err := net.DialUDP("udp", nil, udpAddr)
if err != nil {
    fmt.Println("Failed to dial UDP relay:", err)
    return
}
defer udpConn.Close()

fmt.Printf("UDP relay established to %s\n", relayAddr)

// Listen for local UDP packets and forward them to the server's UDP relay
go func() {
    localUDPAddr := &net.UDPAddr{
        IP:   net.ParseIP("0.0.0.0"),
        Port: 0, // Let the system choose an available port
    }
    localUDPConn, err := net.ListenUDP("udp", localUDPAddr)
    if err != nil {
        fmt.Println("Failed to listen on local UDP:", err)
        return
    }
    defer localUDPConn.Close()

    fmt.Printf("Local UDP relay listening on %s\n", localUDPConn.LocalAddr().String())

    buffer := make([]byte, 65535)
    for {
        n, addr, err := localUDPConn.ReadFromUDP(buffer)
        if err != nil {
            fmt.Println("Error reading from local UDP:", err)
            return
        }

        // Wrap the UDP packet in SOCKS5 UDP request format
        socks5Packet, err := createSocks5UDPRequest(addr, buffer[:n])
        if err != nil {
            fmt.Println("Failed to create SOCKS5 UDP request:", err)
            continue
        }

        _, err = udpConn.Write(socks5Packet)
        if err != nil {
            fmt.Println("Failed to send UDP data to server:", err)
            continue
        }

        fmt.Printf("Forwarded UDP packet from %s to server's UDP relay\n", addr.String())
    }
}()

// Listen for UDP packets from the server's UDP relay and forward them to the local application
buffer := make([]byte, 65535)
for {
    n, _, err := udpConn.ReadFromUDP(buffer)
    if err != nil {
        fmt.Println("Error reading from UDP relay:", err)
        return
    }

    // Parse SOCKS5 UDP response
    socks5Response, err := parseSocks5UDPResponse(buffer[:n])
    if err != nil {
        fmt.Println("Failed to parse SOCKS5 UDP response:", err)
        continue
    }

    // Send the UDP payload to the local application
    go func(data []byte, targetAddr *net.UDPAddr) {
        // Establish connection to the local application

        _, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")

        if err != nil {
            fmt.Println("Failed to resolve local UDP address:", err)
            return
        }
        localConn, err := net.DialUDP("udp", nil, targetAddr)
        if err != nil {
            fmt.Println("Failed to dial local UDP:", err)
            return
        }
        defer localConn.Close()

        _, err = localConn.Write(data)
        if err != nil {
            fmt.Println("Failed to send UDP data to local application:", err)
            return
        }

        fmt.Printf("Forwarded UDP response to local application: %s\n", targetAddr.String())
    }(socks5Response.data, socks5Response.sourceAddr)
}
}

// Create SOCKS5 UDP request packet
func createSocks5UDPRequest(addr *net.UDPAddr, data []byte) ([]byte, error) {
    var buf bytes.Buffer
    // SOCKS5 UDP request header
    // +----+------+------+----------+----------+----------+
    // |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
    // +----+------+------+----------+----------+----------+
    // |  2 |   1  |   1  | Variable |    2     | Variable |
    // +----+------+------+----------+----------+----------+
    buf.Write([]byte{0x00, 0x00}) // RSV
    buf.WriteByte(0x00)            // FRAG
    switch {
    case addr.IP.To4() != nil:
        buf.WriteByte(0x01) // ATYP = IPv4
        buf.Write(addr.IP.To4())
    case addr.IP.To16() != nil:
        buf.WriteByte(0x04) // ATYP = IPv6
        buf.Write(addr.IP.To16())
    default:
        return nil, errors.New("invalid IP address")
    }
    portBytes := make([]byte, 2)
    binary.BigEndian.PutUint16(portBytes, uint16(addr.Port))
    buf.Write(portBytes)
    buf.Write(data)
    return buf.Bytes(), nil
}

// Parse SOCKS5 UDP response packet
type Socks5UDPResponse struct {
    sourceAddr *net.UDPAddr
    data       []byte
}

func parseSocks5UDPResponse(packet []byte) (*Socks5UDPResponse, error) {
    if len(packet) < 10 {
        return nil, errors.New("invalid SOCKS5 UDP response length")
    }
    reader := bytes.NewReader(packet)
    var ver, rsv, atyp byte
    err := binary.Read(reader, binary.BigEndian, &ver)
    if err != nil {
        return nil, err
    }
    err = binary.Read(reader, binary.BigEndian, &rsv)
    if err != nil {
        return nil, err
    }
    err = binary.Read(reader, binary.BigEndian, &atyp)
    if err != nil {
        return nil, err
    }


Copy code
var addr string
var ip net.IP
switch atyp {
case 0x01:
    // IPv4
    ipBytes := make([]byte, 4)
    _, err := io.ReadFull(reader, ipBytes)
    if err != nil {
        return nil, err
    }
    ip = net.IP(ipBytes)
    addr = ip.String()
case 0x03:
    // Domain name
    var domainLen byte
    err := binary.Read(reader, binary.BigEndian, &domainLen)
    if err != nil {
        return nil, err
    }
    domain := make([]byte, domainLen)
    _, err = io.ReadFull(reader, domain)
    if err != nil {
        return nil, err
    }
    addr = string(domain)
case 0x04:
    // IPv6
    ipBytes := make([]byte, 16)
    _, err := io.ReadFull(reader, ipBytes)
    if err != nil {
        return nil, err
    }
    ip = net.IP(ipBytes)
    addr = ip.String()
default:
    return nil, errors.New("unsupported ATYP in SOCKS5 UDP response")
}

// Read port
var port uint16
err = binary.Read(reader, binary.BigEndian, &port)
if err != nil {
    return nil, err
}

sourceAddr := &net.UDPAddr{
    IP:   net.ParseIP(addr),
    Port: int(port),
}

// Read the remaining data
data, err := io.ReadAll(reader)
if err != nil {
    return nil, err
}

return &Socks5UDPResponse{
    sourceAddr: sourceAddr,
    data:       data,
}, nil
}

// Get the host part of an address (without the port)
func getHost(addr string) string {
    host, _, err := net.SplitHostPort(addr)
    if err != nil {
        fmt.Println("Failed to parse server address:", err)
        return addr // Return original address if parsing fails
    }
    return host
}

// Check if the error is "use of closed network connection"
func isClosedNetworkError(err error) bool {
    if err == nil {
        return false
    }
    return strings.Contains(err.Error(), "use of closed network connection")
}

-----end-----

帮我看下socks5代理的udp支持还有问题

我的测试代码如下：
udp服务端：
import socket

def start_udp_server(host='0.0.0.0', port=6789):
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
        s.bind((host, port))
        print(f"UDP server listening on {host}:{port}")


Copy code
    while True:
        data, addr = s.recvfrom(1024)
        print(f"Received message from {addr}: {data.decode()}")
        s.sendto(f"Server received: {data.decode()}".encode(), addr)
if name == "main":
    start_udp_server()

udp客户端:
import socket
import socks  

#print("!!!")

def send_udp_message(message, address, port):
    # 创建一个UDP套接字
    sock = socks.socksocket(socket.AF_INET, socket.SOCK_DGRAM)


Copy code
# 设置 SOCKS5 代理，包括认证信息
sock.set_proxy(socks.SOCKS5, "hub.994455.xyz", 10101, 
            username="yoyo", password="123456")

try:
    # 发送消息
    sock.sendto(message.encode(), (address, port))
    print("消息已发送")
    
    # 接收响应
    response, _ = sock.recvfrom(4096)
    print("接收到的响应:", response.decode())
finally:
    # 关闭套接字
    sock.close()
要发送的消息
message = "Hello, UDP Server!"

服务器地址
server_address = "tunnel1.docip.net"

服务器端口
server_port = 6789

send_udp_message(message, server_address, server_port)

执行客户端的测试代码显示：
root@VM-4-17-ubuntu:/opt/hzsrv# python3 test.py 
消息已发送

但是udp测试服务端并没有显示收到

root@VM-4-17-ubuntu:/opt/hzsrv# ./server
Proxy service listener started on port: 10101
Client connection listener started on port: 10102
Client [yoyo] connected
Received SOCKS5 methods: [0 2]
Allocated UDP relay port 36713 for client [yoyo]
Error reading from UDP relay: read udp [::]:36713: use of closed network connection

注意不要给我留todo，待完善的代码，直接一步到位发我完整的功能没问题的没有bug的代码给我
最后叮嘱发我之前尽量确保可以编译通过