From 59e7057fe961ec69fef1c634e961a711c50eed39 Mon Sep 17 00:00:00 2001 From: "rui.zheng" Date: Mon, 11 Jan 2016 11:31:23 +0800 Subject: [PATCH 1/3] fix websocket crash --- ws.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ws.go b/ws.go index dafb42c..c5fc21d 100644 --- a/ws.go +++ b/ws.go @@ -129,15 +129,18 @@ func (s *ws) handle(w http.ResponseWriter, r *http.Request) { } func (s *ws) ListenAndServe() error { - http.HandleFunc("/ws", s.handle) - return http.ListenAndServe(s.arg.Addr, nil) + sm := http.NewServeMux() + sm.HandleFunc("/ws", s.handle) + return http.ListenAndServe(s.arg.Addr, sm) } func (s *ws) listenAndServeTLS() error { - http.HandleFunc("/ws", s.handle) + sm := http.NewServeMux() + sm.HandleFunc("/ws", s.handle) server := &http.Server{ Addr: s.arg.Addr, TLSConfig: &tls.Config{Certificates: []tls.Certificate{s.arg.Cert}}, + Handler: sm, } return server.ListenAndServeTLS("", "") } From a482f258da031c0cc441330ea7bc52d439b19125 Mon Sep 17 00:00:00 2001 From: "rui.zheng" Date: Thu, 4 Feb 2016 18:01:14 +0800 Subject: [PATCH 2/3] fix udp over tcp --- README.md | 4 +- conn.go | 20 ++++++++- socks.go | 127 +++++++++++++++++++++++------------------------------- 3 files changed, 76 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index aa087da..8676d95 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ gost -L=:8080 -F=socks://server_ip:1080 如果两端都是gost(如上)则数据传输会被加密(使用tls或tls-auth方法),否则使用标准socks5进行通讯(no-auth或user/pass方法)。 #### shadowsocks -gost对shadowsocks的支持是基于[shadowsocks-go](https://github.com/shadowsocks/shadowsocks-go)库。 +gost对shadowsocks加密方法的支持是基于[shadowsocks-go](https://github.com/shadowsocks/shadowsocks-go)库。 服务端: ```bash @@ -130,7 +130,7 @@ gost -L=ss://aes-128-cfb:123456@:8338 gost -L=:8080 -F=ss://aes-128-cfb:123456@server_ip:8338 ``` -gost内置了tls证书,如果需要使用其他tls证书,在gost目录放置key.pem(公钥)和cert.pem(私钥)两个文件即可。 +gost内置了tls证书,如果需要使用其他tls证书,在gost目录放置cert.pem(公钥)和key.pem(私钥)两个文件即可。 SOCKS5 UDP数据处理 ------ diff --git a/conn.go b/conn.go index d20131b..e7e22a6 100644 --- a/conn.go +++ b/conn.go @@ -16,6 +16,7 @@ import ( "net/url" "strconv" "strings" + "sync" "sync/atomic" "time" ) @@ -24,6 +25,21 @@ var ( connCounter int32 ) +var ( + // tcp buffer pool + tcpPool = sync.Pool{ + New: func() interface{} { + return make([]byte, 16*1024) + }, + } + // udp buffer pool + udpPool = sync.Pool{ + New: func() interface{} { + return make([]byte, 64*1024+262) + }, + } +) + func listenAndServe(arg Args) error { var ln net.Listener var err error @@ -120,7 +136,9 @@ func handleConn(conn net.Conn, arg Args) { // http + socks5 - b := make([]byte, 16*1024) + //b := make([]byte, 16*1024) + b := tcpPool.Get().([]byte) + defer tcpPool.Put(b) n, err := io.ReadAtLeast(conn, b, 2) if err != nil { diff --git a/socks.go b/socks.go index e29ff85..1b6ae77 100644 --- a/socks.go +++ b/socks.go @@ -7,6 +7,7 @@ import ( "github.com/ginuerzh/gosocks5" "github.com/golang/glog" "io" + "io/ioutil" "net" "net/url" "strconv" @@ -18,6 +19,10 @@ const ( MethodTLSAuth uint8 = 0x82 // extended method for tls+auth ) +const ( + CmdUdpTun uint8 = 0xf3 // extended method for udp over tcp +) + type clientSelector struct { methods []uint8 user *url.Userinfo @@ -193,7 +198,7 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn) { } else { serveBind(conn) } - case gosocks5.CmdUdp: + case gosocks5.CmdUdp, CmdUdpTun: glog.V(LINFO).Infoln("[socks5] UDP ASSOCIATE", req.Addr) uconn, err := net.ListenUDP("udp", nil) if err != nil { @@ -211,7 +216,6 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn) { addr := ToSocksAddr(uconn.LocalAddr()) addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) - glog.V(LINFO).Infoln("[socks5] UDP listen on", addr) rep := gosocks5.NewReply(gosocks5.Succeeded, addr) if err := rep.Write(conn); err != nil { @@ -219,42 +223,67 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn) { return } else { glog.V(LDEBUG).Infoln(rep) + glog.V(LINFO).Infoln("[socks5] UDP listen on", addr) } - cc, dgram, err := createClientConn(conn, uconn) - if err != nil { - glog.V(LWARNING).Infoln("socks5 udp:", err) - return - } - glog.V(LINFO).Infof("[udp] to %s, length %d", dgram.Header.Addr, len(dgram.Data)) + var cc *UDPConn + var dgram *gosocks5.UDPDatagram + if req.Cmd == CmdUdpTun { + dgram, err = gosocks5.ReadUDPDatagram(conn) + if err != nil { + glog.V(LWARNING).Infoln("socks5 udp:", err) + return + } + cc = Client(conn, nil) + glog.V(LINFO).Infof("[udp] tunnel to %s, length %d", dgram.Header.Addr, len(dgram.Data)) + } else { + b := udpPool.Get().([]byte) + defer udpPool.Put(b) - raddr, err := net.ResolveUDPAddr("udp", dgram.Header.Addr.String()) - if err != nil { - glog.V(LWARNING).Infoln("socks5 udp:", err) - return + n, raddr, err := uconn.ReadFromUDP(b) + if err != nil { + glog.V(LWARNING).Infoln("socks5 udp:", err) + return + } + dgram, err = gosocks5.ReadUDPDatagram(bytes.NewReader(b[:n])) + if err != nil { + glog.V(LWARNING).Infoln("socks5 udp:", err) + return + } + cc = Client(uconn, raddr) + glog.V(LINFO).Infof("[udp] %s -> %s, length %d", raddr, dgram.Header.Addr, len(dgram.Data)) } - sc, err := createServerConn(uconn, raddr) + + sc, err := createServerConn(uconn) if err != nil { glog.V(LWARNING).Infoln("socks5 udp:", err) return } - if err = sc.WriteUDPTimeout(dgram, time.Second*30); err != nil { + if err = sc.WriteUDPTimeout(dgram, time.Second*60); err != nil { glog.V(LWARNING).Infoln("socks5 udp:", err) return } - dgram, err = sc.ReadUDPTimeout(time.Second * 30) + dgram, err = sc.ReadUDPTimeout(time.Second * 60) if err != nil { glog.V(LWARNING).Infoln("socks5 udp:", err) return } glog.V(LINFO).Infof("[udp] from %s, length %d", dgram.Header.Addr, len(dgram.Data)) - if err = cc.WriteUDPTimeout(dgram, time.Second*30); err != nil { + if err = cc.WriteUDPTimeout(dgram, time.Second*60); err != nil { glog.V(LWARNING).Infoln("socks5 udp:", err) return } + if req.Cmd == gosocks5.CmdUdp { + go func() { + ioutil.ReadAll(conn) + cc.Close() + sc.Close() + glog.V(LINFO).Infoln("[udp] transfer done") + }() + } TransportUDP(cc, sc) default: glog.V(LWARNING).Infoln("Unrecognized request: ", req) @@ -334,7 +363,7 @@ func forwardBind(req *gosocks5.Request, conn net.Conn) error { defer fconn.Close() if err := req.Write(fconn); err != nil { - glog.V(LWARNING).Infoln("[socks5] BIND(forward)", err) + glog.V(LWARNING).Infoln("[socks5] BIND forward", err) gosocks5.NewReply(gosocks5.Failure, nil).Write(conn) return err } @@ -377,53 +406,7 @@ func peekReply(dst io.Writer, src io.Reader) (rep *gosocks5.Reply, err error) { return } -func createClientConn(conn net.Conn, uconn *net.UDPConn) (c *UDPConn, dgram *gosocks5.UDPDatagram, err error) { - var raddr *net.UDPAddr - dgramChan := make(chan *gosocks5.UDPDatagram, 1) - errChan := make(chan error, 1) - go func() { - b := make([]byte, 64*1024+262) - - n, addr, err := uconn.ReadFromUDP(b) - if err != nil { - errChan <- err - return - } - raddr = addr - - dgram, err := gosocks5.ReadUDPDatagram(bytes.NewReader(b[:n])) - if err != nil { - errChan <- err - return - } - dgramChan <- dgram - }() - - go func() { - dgram, err := gosocks5.ReadUDPDatagram(conn) - if err != nil { - errChan <- err - return - } - dgramChan <- dgram - }() - - select { - case dgram = <-dgramChan: - if raddr != nil { - glog.V(LINFO).Infoln("[udp] client", raddr) - c = Client(uconn, raddr) - } else { - glog.V(LINFO).Infoln("[udp] tunnel") - c = Client(conn, nil) - } - case err = <-errChan: - } - - return -} - -func createServerConn(uconn *net.UDPConn, addr net.Addr) (c *UDPConn, err error) { +func createServerConn(uconn *net.UDPConn) (c *UDPConn, err error) { if len(forwardArgs) == 0 { c = Server(uconn) return @@ -436,9 +419,9 @@ func createServerConn(uconn *net.UDPConn, addr net.Addr) (c *UDPConn, err error) } return } - glog.V(LINFO).Infoln("forward udp associate") + glog.V(LINFO).Infoln("[udp] forward associate") - req := gosocks5.NewRequest(gosocks5.CmdUdp, nil) + req := gosocks5.NewRequest(CmdUdpTun, nil) if err = req.Write(fconn); err != nil { fconn.Close() return @@ -455,7 +438,7 @@ func createServerConn(uconn *net.UDPConn, addr net.Addr) (c *UDPConn, err error) fconn.Close() return nil, errors.New("Failure") } - glog.V(LINFO).Infoln("forward udp associate, on", rep.Addr, "OK") + glog.V(LINFO).Infoln("[udp] forward associate on", rep.Addr, "OK") c = Server(fconn) return @@ -477,13 +460,13 @@ func PipeUDP(src, dst *UDPConn, ch chan<- error) { for { var dgram *gosocks5.UDPDatagram - dgram, err = src.ReadUDP() + dgram, err = src.ReadUDPTimeout(time.Second * 60) if err != nil { break } - // glog.V(LDEBUG).Infof("[udp] addr %s, length %d", dgram.Header.Addr, len(dgram.Data)) + glog.V(LDEBUG).Infof("[udp] addr %s, length %d", dgram.Header.Addr, len(dgram.Data)) - if err = dst.WriteUDP(dgram); err != nil { + if err = dst.WriteUDPTimeout(dgram, time.Second*60); err != nil { break } } @@ -501,9 +484,9 @@ func TransportUDP(cc, sc *UDPConn) (err error) { select { case err = <-wChan: - //log.Println("w exit", err) + // glog.V(LDEBUG).Infoln("w exit", err) case err = <-rChan: - //log.Println("r exit", err) + // glog.V(LDEBUG).Infoln("r exit", err) } return From ee1fb89b8cd8a03a141d0afaaf0ae8537e1ff73f Mon Sep 17 00:00:00 2001 From: "rui.zheng" Date: Fri, 5 Feb 2016 15:23:57 +0800 Subject: [PATCH 3/3] fix bug #27 --- conn.go | 2 +- main.go | 2 +- socks.go | 45 ++++++++++++++++++++++++--------------------- udp.go | 5 ++++- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/conn.go b/conn.go index e7e22a6..94908f3 100644 --- a/conn.go +++ b/conn.go @@ -232,7 +232,7 @@ func Connect(addr string) (conn net.Conn, err error) { func forwardChain(chain ...Args) (conn net.Conn, end Args, err error) { end = chain[0] - if conn, err = net.DialTimeout("tcp", end.Addr, time.Second*30); err != nil { + if conn, err = net.DialTimeout("tcp", end.Addr, time.Second*90); err != nil { return } c, err := forward(conn, end) diff --git a/main.go b/main.go index 50919ad..9a5aaff 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,7 @@ const ( ) const ( - Version = "2.0-rc2" + Version = "2.0-rc3" ) var ( diff --git a/socks.go b/socks.go index 1b6ae77..ad04e54 100644 --- a/socks.go +++ b/socks.go @@ -235,7 +235,7 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn) { return } cc = Client(conn, nil) - glog.V(LINFO).Infof("[udp] tunnel to %s, length %d", dgram.Header.Addr, len(dgram.Data)) + glog.V(LINFO).Infof("[udp] -> %s, length %d", dgram.Header.Addr, len(dgram.Data)) } else { b := udpPool.Get().([]byte) defer udpPool.Put(b) @@ -259,32 +259,31 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn) { glog.V(LWARNING).Infoln("socks5 udp:", err) return } + defer sc.Close() - if err = sc.WriteUDPTimeout(dgram, time.Second*60); err != nil { + if err = sc.WriteUDPTimeout(dgram, time.Second*90); err != nil { glog.V(LWARNING).Infoln("socks5 udp:", err) return } - dgram, err = sc.ReadUDPTimeout(time.Second * 60) + dgram, err = sc.ReadUDPTimeout(time.Second * 90) if err != nil { glog.V(LWARNING).Infoln("socks5 udp:", err) return } - glog.V(LINFO).Infof("[udp] from %s, length %d", dgram.Header.Addr, len(dgram.Data)) + glog.V(LINFO).Infof("[udp] <- %s, length %d", dgram.Header.Addr, len(dgram.Data)) - if err = cc.WriteUDPTimeout(dgram, time.Second*60); err != nil { + if err = cc.WriteUDPTimeout(dgram, time.Second*90); err != nil { glog.V(LWARNING).Infoln("socks5 udp:", err) return } if req.Cmd == gosocks5.CmdUdp { - go func() { - ioutil.ReadAll(conn) - cc.Close() - sc.Close() - glog.V(LINFO).Infoln("[udp] transfer done") - }() + go TransportUDP(cc, sc) + ioutil.ReadAll(conn) // wait for client exit + glog.V(LINFO).Infoln("[udp] transfer done") + } else { + TransportUDP(cc, sc) } - TransportUDP(cc, sc) default: glog.V(LWARNING).Infoln("Unrecognized request: ", req) } @@ -317,6 +316,7 @@ func serveBind(conn net.Conn) error { glog.V(LDEBUG).Infoln(rep) glog.V(LINFO).Infoln("[socks5] BIND on", addr, "OK") + l.SetDeadline(time.Now().Add(time.Minute * 30)) // wait 30 minutes at most tconn, err := l.AcceptTCP() l.Close() // only accept one peer if err != nil { @@ -348,7 +348,7 @@ func serveBind(conn net.Conn) error { func forwardBind(req *gosocks5.Request, conn net.Conn) error { fconn, _, err := forwardChain(forwardArgs...) if err != nil { - glog.V(LWARNING).Infoln("[socks5] BIND(forward)", req.Addr, err) + glog.V(LWARNING).Infoln("[socks5] BIND forward", req.Addr, err) if fconn != nil { fconn.Close() } @@ -372,18 +372,18 @@ func forwardBind(req *gosocks5.Request, conn net.Conn) error { // first reply rep, err := peekReply(conn, fconn) if err != nil { - glog.V(LWARNING).Infoln("[socks5] BIND(forward)", err) + glog.V(LWARNING).Infoln("[socks5] BIND forward", err) return err } - glog.V(LINFO).Infoln("[socks5] BIND(forward) on", rep.Addr, "OK") + glog.V(LINFO).Infoln("[socks5] BIND forward on", rep.Addr, "OK") // second reply rep, err = peekReply(conn, fconn) if err != nil { - glog.V(LWARNING).Infoln("[socks5] BIND(forward) accept", err) + glog.V(LWARNING).Infoln("[socks5] BIND forward accept", err) return err } - glog.V(LINFO).Infoln("[socks5] BIND(forward) accept", rep.Addr) + glog.V(LINFO).Infoln("[socks5] BIND forward accept", rep.Addr) return Transport(conn, fconn) } @@ -460,13 +460,16 @@ func PipeUDP(src, dst *UDPConn, ch chan<- error) { for { var dgram *gosocks5.UDPDatagram - dgram, err = src.ReadUDPTimeout(time.Second * 60) + dgram, err = src.ReadUDP() if err != nil { break } - glog.V(LDEBUG).Infof("[udp] addr %s, length %d", dgram.Header.Addr, len(dgram.Data)) - - if err = dst.WriteUDPTimeout(dgram, time.Second*60); err != nil { + if src.isClient { + glog.V(LDEBUG).Infof("[udp] -> %s, length %d", dgram.Header.Addr, len(dgram.Data)) + } else { + glog.V(LDEBUG).Infof("[udp] <- %s, length %d", dgram.Header.Addr, len(dgram.Data)) + } + if err = dst.WriteUDP(dgram); err != nil { break } } diff --git a/udp.go b/udp.go index e3ce064..7ddeac1 100644 --- a/udp.go +++ b/udp.go @@ -72,7 +72,10 @@ func (c *UDPConn) readUDPClient() (*gosocks5.UDPDatagram, error) { func (c *UDPConn) readUDPServer() (*gosocks5.UDPDatagram, error) { if c.udp != nil { - b := make([]byte, 65535) + // b := make([]byte, 65535) + b := udpPool.Get().([]byte) + defer udpPool.Put(b) + n, addr, err := c.udp.ReadFrom(b) if err != nil { return nil, err