2

I'm trying to make a proxy:

I need to listen to port 1080 (socks 5), and complete a request to a destination using an external ip:port socks 5, I managed to open this connection with the external ip, but I don't know how I could complete the request to the target destination using that external ip.

could someone help me with this?

package main

import (
    "bufio"
    "errors"
    "fmt"
    "io"
    "log"
    "net"
)

const (
    ConnectCommand   = uint8(1)
    BindCommand      = uint8(2)
    AssociateCommand = uint8(3)
    ipv4Address      = uint8(1)
    fqdnAddress      = uint8(3)
    ipv6Address      = uint8(4)
)

type AddrSpec struct {
    FQDN string
    IP   net.IP
    Port int
}

func main() {
    l, err := net.Listen("tcp", "127.0.0.1:1080")
    if err != nil {
        fmt.Print(err)
    }
    defer l.Close()

    for {
        conn, err := l.Accept()
        if err != nil {
            fmt.Print(err)
        }

        go handle(conn)
    }
}

func handle(conn net.Conn) {
    defer func() {
        _ = conn.Close()
    }()

    bufConn := bufio.NewReader(conn)
    version := []byte{0}
    if _, err := bufConn.Read(version); err != nil {
        log.Fatalf("cannot read version: %s", err.Error())
    }

    if version[0] != uint8(5) {
        log.Fatalf("unsupported SOCKS version: %v", version)
    }

    socks5ExternalConn, err := net.Dial("tcp", externalSOCKS5Proxy())
    if err != nil {
        log.Printf("Connection error: %s", err.Error())
    }

    dest, err := readAddrSpec(bufConn)
    if err != nil {
    }

    // how i can send request to server with external conn?
}

func externalSOCKS5Proxy() string {
    return "externalip:externalport"
}

func readAddrSpec(r io.Reader) (*AddrSpec, error) {
    d := &AddrSpec{}

    // Get the address type
    addrType := []byte{0}
    if _, err := r.Read(addrType); err != nil {
        return nil, err
    }

    // Handle on a per type basis
    switch addrType[0] {
    case ipv4Address:
        addr := make([]byte, 4)
        if _, err := io.ReadAtLeast(r, addr, len(addr)); err != nil {
            return nil, err
        }
        d.IP = net.IP(addr)

    case ipv6Address:
        addr := make([]byte, 16)
        if _, err := io.ReadAtLeast(r, addr, len(addr)); err != nil {
            return nil, err
        }
        d.IP = net.IP(addr)

    case fqdnAddress:
        if _, err := r.Read(addrType); err != nil {
            return nil, err
        }
        addrLen := int(addrType[0])
        fqdn := make([]byte, addrLen)
        if _, err := io.ReadAtLeast(r, fqdn, addrLen); err != nil {
            return nil, err
        }
        d.FQDN = string(fqdn)

    default:
        return nil, errors.New("unrecognizedAddrType")
    }

    // Read the port
    port := []byte{0, 0}
    if _, err := io.ReadAtLeast(r, port, 2); err != nil {
        return nil, err
    }
    d.Port = (int(port[0]) << 8) | int(port[1])

    return d, nil
}
Ming
  • 1,349
  • 4
  • 13
  • 36
  • What have you tried? A good starting point might be one of the existing SOCKS 5 implementations ([e.g.](https://github.com/tailscale/tailscale/blob/v1.34.2/net/socks5/socks5.go#L165)). – Brits Jan 05 '23 at 22:34
  • @Brits I was confused how I could listen to a local port and send a request to the target with the ip and port of an external connection, could you help me with this implementation, is this possible? – Ming Jan 06 '23 at 00:09
  • Take a look at the [example I linked](https://github.com/tailscale/tailscale/blob/v1.34.2/net/socks5/socks5.go#L165) - there is a bit too much to cover in a Stack overflow answer (because you need to send the response header etc). If you ignore the header then you are just copying data between the two connections (so basically two go routines, one to receive from requester and one to receive from external connection). – Brits Jan 06 '23 at 04:45
  • wouldn't that be 3 go routines? example: from external_ip to localhost:1080 from external_ip to target from target to external_ip @Brits – Ming Jan 07 '23 at 16:19
  • or am i passing myself off on something? – Ming Jan 07 '23 at 16:19
  • Unless I'm missing something here you will have two connections - client to proxy and proxy to external ip so two goroutines (receive from connection, echo to other connection). – Brits Jan 07 '23 at 18:42
  • so, I'm going to listen to a port 1080 that will receive a connection that has an external ip on port 7777 as destination, and I need to send a connection command on that external ip: 7777 with an ip that's also external (the ip of the socks proxy server 5 ) , other than localhost. – Ming Jan 07 '23 at 18:53
  • that is, these connections that I will listen to on port 1080, are destined for an external ip on port 7777, which I need to send a connection command with an ip different from mine (from a socks 5 proxy server) – Ming Jan 07 '23 at 18:56
  • I just got it, I used proxy.Socks5 and the dialect dial, with that the connection command was sent by the external ip to the external ip – Ming Jan 07 '23 at 20:01
  • Great. Note that listening on `127.0.0.1:1080` will only allow connections from apps running on your PC; to allow other things to connect listen on `:1080` (or a specific interface address). – Brits Jan 07 '23 at 22:09

0 Answers0