แสดงบทความที่มีป้ายกำกับ socks server แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ socks server แสดงบทความทั้งหมด

วันอังคารที่ 2 มิถุนายน พ.ศ. 2558

golang SOCKS5 server

ไหนๆวันนี้ก็เขียนเรื่อง go SOCKS client ไปแล้วเขียนเรืองทำ SOCKS server ด้วย go ไปเลยดีกว่าเพราะเห็น Bright มากด like ให้ด้วยเห็นวันก่อนถามเรื่องทำ SOCKS server นิ

package main

import "github.com/armon/go-socks5"

func main(){
conf := &socks5.Config{}
server, err := socks5.New(conf)
if err != nil {
  panic(err)
}

// Create SOCKS5 proxy on localhost port 8000
if err := server.ListenAndServe("tcp", "127.0.0.1:8000"); err != nil {
  panic(err)
        }
}

lib ตัวนี้เป็น SOCKS5 อย่างเดียวเวลา connect ให้ตั้ง type เป็น SOCKS5 ด้วยนะเวลาจะทดสอบ


ตามรูปตัวอย่างบรรทัดด้านบนเป็นการลองส่ง  request จาก client ที่ set SOCKS 4 มาจะเห็นว่า connect ไม่ได้ ถ้า set ถูกจะเห็นตามบรรทัดล่างๆคือ มีการส่งข้อมูลไปกลับระหว่าตัว client กับ target 
แค่นี้ยังไม่พอเรามา hack เพิ่มอีกนิดหน่อยดีกว่า จริงๆผมอยาก print log มากกว่านี้แต่ ไปอ่านdoc มันแล้วไม่มี function พวกนี้เลย เรามาเขียน ความสามารถที่เราอยากได้เพิ่มให้กับ lib มันเลยดีกว่า
โดยเข้าไปแก้ file ที่อยู่ใน path src/github.com/armon/go-socks5/request.go
หรือถ้าต้องการ monitor อะไรเพิ่มเติมก็ไปเขียน hook เพิ่มเอาได้เลย


func (s *Server) handleConnect(conn conn, bufConn io.Reader, dest, realDest *AddrSpec) error {
        // Check if this is allowed
        client := conn.RemoteAddr().(*net.TCPAddr)
        if !s.config.Rules.AllowConnect(realDest.IP, realDest.Port, client.IP, client.Port) {
                if err := sendReply(conn, ruleFailure, nil); err != nil {
                        return fmt.Errorf("Failed to send reply: %v", err)
                }
                return fmt.Errorf("Connect to %v blocked by rules", dest)
        }

        // Attempt to connect
        addr := net.TCPAddr{IP: realDest.IP, Port: realDest.Port}
        target, err := net.DialTCP("tcp", nil, &addr)
        if err != nil {
                msg := err.Error()
                resp := hostUnreachable
                if strings.Contains(msg, "refused") {
                        resp = connectionRefused
                } else if strings.Contains(msg, "network is unreachable") {
                        resp = networkUnreachable
                }
                if err := sendReply(conn, resp, nil); err != nil {
                        return fmt.Errorf("Failed to send reply: %v", err)
                }
                return fmt.Errorf("Connect to %v failed: %v", dest, err)
        }
        defer target.Close()

        // Send success
        local := target.LocalAddr().(*net.TCPAddr)
        bind := AddrSpec{IP: local.IP, Port: local.Port}
        if err := sendReply(conn, successReply, &bind); err != nil {
                return fmt.Errorf("Failed to send reply: %v", err)
        }

        // Start proxying
        errCh := make(chan error, 2)
        go proxy("target", target, bufConn, errCh,realDest.IP)
        go proxy("client", conn, target, errCh,local.IP)

        // Wait
        select {
        case e := <-errCh:
                return e
        }
}

function handleConnection เพิ่งตรงให้ go routine เรียก function โดยเพิ่มตัวแปร IP เข้าไปด้วย


func proxy(name string, dst io.Writer, src io.Reader, errCh chan error,ip1 net.IP) {
        // Copy
        n, err := io.Copy(dst, src)

        // Log, and sleep. This is jank but allows the otherside
        // to finish a pending copy
        log.Printf("[DEBUG] socks: Copied %d bytes to %s[%v]", n, name,ip1)
        time.Sleep(10 * time.Millisecond)

        // Send any errors
        errCh <-err
}
และที่ function proxy ให้รับตัวแปรเพิ่มอีก 1 ตัวและ print log IP ออกมาแสดง
จะได้ผลตามนี้


แค่ code ไม่กี่บรรทัดก็ได้ SOCKS server แล้ว