ไหนๆวันนี้ก็เขียนเรื่อง 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 แล้ว