Skip to content

Instantly share code, notes, and snippets.

@magicjva
Forked from felix021/socks5_proxy.go
Created July 3, 2022 03:03
Show Gist options
  • Select an option

  • Save magicjva/2bb08da919ba65c72c835b24d07eb62b to your computer and use it in GitHub Desktop.

Select an option

Save magicjva/2bb08da919ba65c72c835b24d07eb62b to your computer and use it in GitHub Desktop.

Revisions

  1. @felix021 felix021 revised this gist Nov 21, 2020. No changes.
  2. @felix021 felix021 created this gist Nov 21, 2020.
    145 changes: 145 additions & 0 deletions socks5_proxy.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,145 @@
    package main

    import (
    "encoding/binary"
    "errors"
    "fmt"
    "io"
    "net"
    )

    func main() {
    server, err := net.Listen("tcp", ":1080")
    if err != nil {
    fmt.Printf("Listen failed: %v\n", err)
    return
    }

    for {
    client, err := server.Accept()
    if err != nil {
    fmt.Printf("Accept failed: %v", err)
    continue
    }
    go process(client)
    }
    }

    func process(client net.Conn) {
    if err := Socks5Auth(client); err != nil {
    fmt.Println("auth error:", err)
    client.Close()
    return
    }

    target, err := Socks5Connect(client)
    if err != nil {
    fmt.Println("connect error:", err)
    client.Close()
    return
    }

    Socks5Forward(client, target)
    }

    func Socks5Auth(client net.Conn) (err error) {
    buf := make([]byte, 256)

    // 读取 VER 和 NMETHODS
    n, err := io.ReadFull(client, buf[:2])
    if n != 2 {
    return errors.New("reading header: " + err.Error())
    }

    ver, nMethods := int(buf[0]), int(buf[1])
    if ver != 5 {
    return errors.New("invalid version")
    }

    // 读取 METHODS 列表
    n, err = io.ReadFull(client, buf[:nMethods])
    if n != nMethods {
    return errors.New("reading methods: " + err.Error())
    }

    //无需认证
    n, err = client.Write([]byte{0x05, 0x00})
    if n != 2 || err != nil {
    return errors.New("write rsp: " + err.Error())
    }

    return nil
    }

    func Socks5Connect(client net.Conn) (net.Conn, error) {
    buf := make([]byte, 256)

    n, err := io.ReadFull(client, buf[:4])
    if n != 4 {
    return nil, errors.New("read header: " + err.Error())
    }

    ver, cmd, _, atyp := buf[0], buf[1], buf[2], buf[3]
    if ver != 5 || cmd != 1 {
    return nil, errors.New("invalid ver/cmd")
    }

    addr := ""
    switch atyp {
    case 1:
    n, err = io.ReadFull(client, buf[:4])
    if n != 4 {
    return nil, errors.New("invalid IPv4: " + err.Error())
    }
    addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])

    case 3:
    n, err = io.ReadFull(client, buf[:1])
    if n != 1 {
    return nil, errors.New("invalid hostname: " + err.Error())
    }
    addrLen := int(buf[0])

    n, err = io.ReadFull(client, buf[:addrLen])
    if n != addrLen {
    return nil, errors.New("invalid hostname: " + err.Error())
    }
    addr = string(buf[:addrLen])

    case 4:
    return nil, errors.New("IPv6: no supported yet")

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

    n, err = io.ReadFull(client, buf[:2])
    if n != 2 {
    return nil, errors.New("read port: " + err.Error())
    }
    port := binary.BigEndian.Uint16(buf[:2])

    destAddrPort := fmt.Sprintf("%s:%d", addr, port)
    dest, err := net.Dial("tcp", destAddrPort)
    if err != nil {
    return nil, errors.New("dial dst: " + err.Error())
    }

    n, err = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
    if err != nil {
    dest.Close()
    return nil, errors.New("write rsp: " + err.Error())
    }

    return dest, nil
    }

    func Socks5Forward(client, target net.Conn) {
    forward := func(src, dest net.Conn) {
    defer src.Close()
    defer dest.Close()
    io.Copy(src, dest)
    }
    go forward(client, target)
    go forward(target, client)
    }