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


package main

import (
    "bufio"
    "bytes"
    "encoding/base64"
    "encoding/binary"
    "errors"
    //"flag"
    "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()

    // 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
    }

    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)
    }()

    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 <-client.disconnect:
            return
        }
    }
}

// Transfer data between two TCP connections
func transferData(conn1, conn2 net.Conn) {
    defer conn1.Close()
    defer conn2.Close()
    done := make(chan struct{}, 2)
    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
    <-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()
        }
    }()

    // 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
    }

    // 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
        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])

    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]

    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
        }
        // DO NOT defer udpListener.Close() here; we need it to stay open
        fmt.Printf("Allocated UDP relay port %d for client [%s]\n", udpListener.LocalAddr().(*net.UDPAddr).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()...)
        relayPort := udpListener.LocalAddr().(*net.UDPAddr).Port
        reply = append(reply, []byte{byte(relayPort >> 8), byte(relayPort & 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, udpConn *net.UDPConn) {
    buffer := make([]byte, 65535)
    for {
        udpConn.SetReadDeadline(time.Now().Add(udpTimeout))
        n, clientAddr, err := udpConn.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)
            udpConn.Close()
            return
        }

        data := buffer[:n]

        // Parse the SOCKS5 UDP request
        socks5Packet, err := parseSocks5UDPRequest(data)
        if err != nil {
            fmt.Println("Failed to parse SOCKS5 UDP request:", err)
            continue
        }

        // Handle the UDP request in a separate goroutine
        go func(clientAddr *net.UDPAddr, socks5Packet *Socks5UDPRequest) {
            forwardUDP(clientAddr, socks5Packet, udpConn)
        }(clientAddr, socks5Packet)
    }
}

// Forward UDP data to the target address and send responses back to the client
func forwardUDP(clientAddr *net.UDPAddr, socks5Packet *Socks5UDPRequest, udpConn *net.UDPConn) {
    targetAddr, err := net.ResolveUDPAddr("udp", socks5Packet.targetAddr)
    if err != nil {
        fmt.Println("Failed to resolve target address:", err)
        return
    }

    // Create a UDP connection from an arbitrary port
    localConn, err := net.ListenUDP("udp", nil)
    if err != nil {
        fmt.Println("Failed to create local UDP connection:", err)
        return
    }
    defer localConn.Close()

    // Send data to the target
    _, err = localConn.WriteToUDP(socks5Packet.data, targetAddr)
    if err != nil {
        fmt.Println("Failed to send UDP data to target:", err)
        return
    }

    // Read response from the target
    buffer := make([]byte, 65535)
    localConn.SetReadDeadline(time.Now().Add(udpTimeout))
    n, addr, err := localConn.ReadFromUDP(buffer)
    if err != nil {
        if ne, ok := err.(net.Error); ok && ne.Timeout() {
            // Timeout, no response
            return
        }
        fmt.Println("Failed to read UDP response from target:", err)
        return
    }
    responseData := buffer[:n]

    // Now send back to the client
    var responseBuf bytes.Buffer
    responseBuf.Write([]byte{0x00, 0x00}) // RSV
    responseBuf.WriteByte(0x00)           // FRAG

    if ip4 := addr.IP.To4(); ip4 != nil {
        responseBuf.WriteByte(0x01) // IPv4
        responseBuf.Write(ip4)
    } else if ip16 := addr.IP.To16(); ip16 != nil {
        responseBuf.WriteByte(0x04) // IPv6
        responseBuf.Write(ip16)
    } else {
        fmt.Println("Unknown IP version")
        return
    }

    portBytes := make([]byte, 2)
    binary.BigEndian.PutUint16(portBytes, uint16(addr.Port))
    responseBuf.Write(portBytes)
    responseBuf.Write(responseData)

    // Send response back to client
    _, err = udpConn.WriteToUDP(responseBuf.Bytes(), clientAddr)
    if err != nil {
        fmt.Println("Failed to send UDP response to client:", err)
        return
    }
}

// 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)
    // Skip RSV and FRAG
    reader.Seek(3, io.SeekStart)

    var atyp byte
    err := binary.Read(reader, binary.BigEndian, &atyp)
    if err != nil {
        return nil, err
    }

    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
}

// 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"
    //"bytes"
    //"encoding/binary"
    //"errors"
    "flag"
    "fmt"
    "io"
    "net"
    "os"
    "strconv"
    "strings"
    "sync"
    "time"
)

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()

    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)

    reader := bufio.NewReader(conn)

    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)
            }
        }
    }
}

func handleNewConn(port int, targetAddr string) {
    // Establish new TCP connection to the assigned port on the server
    // Use the server address provided via command-line
    serverHost := getHost(serverAddr)
    fullAddr := net.JoinHostPort(serverHost, 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)

    // 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)
}

// 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}")
        
        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)
    

    # 设置 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 35264 for client [yoyo]



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