diff --git a/README.md b/README.md index 03793c8..30c2354 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ gost -L=admin:123456@localhost:8080 * 多端口监听 ```bash -gost -L=http://localhost:8080 -L=socks://localhost:8081 -L=ss://aes-256-cfb:123456@:8082 +gost -L=:8080 -L=ss://aes-256-cfb:123456@:8081 ``` ##### 设置转发代理 @@ -88,28 +88,29 @@ gost -L=:8080 -F=http://admin:123456@192.168.1.1:8081 ```bash gost -L=:8080 -F=http://192.168.1.1:8081 -F=socks://192.168.1.2:8082 -F=a.b.c.d:NNNN ``` -gost按照-F设置顺序通过转发链将请求最终转发给a.b.c.d:NNNN处理,每一个转发代理可以是任意一种类型的代理(http/socks5)。 +gost按照-F设置顺序通过转发链将请求最终转发给a.b.c.d:NNNN处理,每一个转发代理可以是任意http/socks5类型代理。 #### SOCKS5 UDP数据处理 ##### 不设置转发代理 - + gost作为标准socks5代理处理UDP数据 ##### 设置转发代理 - + ##### 设置多个转发代理(转发链) -当设置转发代理时,gost会使用UDP over TCP方式转发UDP数据。 +当设置转发代理时,gost会使用UDP-Over-TCP方式转发UDP数据。proxy1 - proxyN可以为任意http/socks5类型代理。 ##### 限制条件 + 如果要转发socks5的BIND和UDP请求,转发链的末端(最后一个-F参数)必须是gost socks5类型代理,且转发链中的http代理必须支持CONNECT方法。 diff --git a/http.go b/http.go index 47a9ee9..80f296c 100644 --- a/http.go +++ b/http.go @@ -34,29 +34,21 @@ func handleHttpRequest(req *http.Request, conn net.Conn, arg Args) { "Proxy-Agent: gost/" + Version + "\r\n\r\n" if _, err := conn.Write([]byte(resp)); err != nil { - if glog.V(LWARNING) { - glog.Warningln(err) - } - } - if glog.V(LDEBUG) { - glog.Infoln(resp) - } - if glog.V(LWARNING) { - glog.Warningln("http: proxy authentication required") + glog.V(LWARNING).Infoln(err) } + glog.V(LDEBUG).Infoln(resp) + + glog.V(LWARNING).Infoln("http: proxy authentication required") return } c, err := Connect(req.Host) if err != nil { - if glog.V(LWARNING) { - glog.Warningln(err) - } + glog.V(LWARNING).Infoln(err) + b := []byte("HTTP/1.1 503 Service unavailable\r\n" + "Proxy-Agent: gost/" + Version + "\r\n\r\n") - if glog.V(LDEBUG) { - glog.Infoln(string(b)) - } + glog.V(LDEBUG).Infoln(string(b)) conn.Write(b) return } @@ -65,13 +57,10 @@ func handleHttpRequest(req *http.Request, conn net.Conn, arg Args) { if req.Method == "CONNECT" { b := []byte("HTTP/1.1 200 Connection established\r\n" + "Proxy-Agent: gost/" + Version + "\r\n\r\n") - if glog.V(LDEBUG) { - glog.Infoln(string(b)) - } + glog.V(LDEBUG).Infoln(string(b)) + if _, err := conn.Write(b); err != nil { - if glog.V(LWARNING) { - glog.Warningln(err) - } + glog.V(LWARNING).Infoln(err) return } } else { @@ -81,9 +70,7 @@ func handleHttpRequest(req *http.Request, conn net.Conn, arg Args) { err = req.Write(c) } if err != nil { - if glog.V(LWARNING) { - glog.Warningln(err) - } + glog.V(LWARNING).Infoln(err) return } } diff --git a/socks.go b/socks.go index 34c4566..3bce504 100644 --- a/socks.go +++ b/socks.go @@ -47,27 +47,19 @@ func (selector *clientSelector) OnSelected(method uint8, conn net.Conn) (net.Con req := gosocks5.NewUserPassRequest(gosocks5.UserPassVer, username, password) if err := req.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 auth:", err) - } + glog.V(LWARNING).Infoln("socks5 auth:", err) return nil, err } - if glog.V(LDEBUG) { - glog.Infoln(req) - } + glog.V(LDEBUG).Infoln(req) - res, err := gosocks5.ReadUserPassResponse(conn) + resp, err := gosocks5.ReadUserPassResponse(conn) if err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 auth:", err) - } + glog.V(LWARNING).Infoln("socks5 auth:", err) return nil, err } - if glog.V(LDEBUG) { - glog.Infoln(res) - } + glog.V(LDEBUG).Infoln(resp) - if res.Status != gosocks5.Succeeded { + if resp.Status != gosocks5.Succeeded { return nil, gosocks5.ErrAuthFailure } case gosocks5.MethodNoAcceptable: @@ -87,9 +79,7 @@ func (selector *serverSelector) Methods() []uint8 { } func (selector *serverSelector) Select(methods ...uint8) (method uint8) { - if glog.V(LDEBUG) { - glog.Infof("%d %d % d", gosocks5.Ver5, len(methods), methods) - } + glog.V(LDEBUG).Infof("%d %d % d", gosocks5.Ver5, len(methods), methods) method = gosocks5.MethodNoAuth for _, m := range methods { @@ -113,9 +103,7 @@ func (selector *serverSelector) Select(methods ...uint8) (method uint8) { } func (selector *serverSelector) OnSelected(method uint8, conn net.Conn) (net.Conn, error) { - if glog.V(LDEBUG) { - glog.Infof("%d %d", gosocks5.Ver5, method) - } + glog.V(LDEBUG).Infof("%d %d", gosocks5.Ver5, method) switch method { case MethodTLS: @@ -128,14 +116,10 @@ func (selector *serverSelector) OnSelected(method uint8, conn net.Conn) (net.Con req, err := gosocks5.ReadUserPassRequest(conn) if err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 auth:", err) - } + glog.V(LWARNING).Infoln("socks5 auth:", err) return nil, err } - if glog.V(LDEBUG) { - glog.Infoln(req.String()) - } + glog.V(LDEBUG).Infoln(req.String()) var username, password string if selector.arg.User != nil { @@ -146,30 +130,21 @@ func (selector *serverSelector) OnSelected(method uint8, conn net.Conn) (net.Con if (username != "" && req.Username != username) || (password != "" && req.Password != password) { resp := gosocks5.NewUserPassResponse(gosocks5.UserPassVer, gosocks5.Failure) if err := resp.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 auth:", err) - } + glog.V(LWARNING).Infoln("socks5 auth:", err) return nil, err } - if glog.V(LDEBUG) { - glog.Infoln(resp) - } - if glog.V(LWARNING) { - glog.Warningln("socks5: proxy authentication required") - } + glog.V(LDEBUG).Infoln(resp) + glog.V(LWARNING).Infoln("socks5: proxy authentication required") + return nil, gosocks5.ErrAuthFailure } resp := gosocks5.NewUserPassResponse(gosocks5.UserPassVer, gosocks5.Succeeded) if err := resp.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 auth:", err) - } + glog.V(LWARNING).Infoln("socks5 auth:", err) return nil, err } - if glog.V(LDEBUG) { - glog.Infoln(resp) - } + glog.V(LDEBUG).Infoln(resp) case gosocks5.MethodNoAcceptable: return nil, gosocks5.ErrBadMethod @@ -179,29 +154,20 @@ func (selector *serverSelector) OnSelected(method uint8, conn net.Conn) (net.Con } func handleSocks5Request(req *gosocks5.Request, conn net.Conn) { - if glog.V(LDEBUG) { - glog.Infoln(req) - } + glog.V(LDEBUG).Infoln(req) switch req.Cmd { case gosocks5.CmdConnect: - if glog.V(LINFO) { - glog.Infoln("socks5 connect:", req.Addr.String()) - } + glog.V(LINFO).Infoln(">>> socks5 connect:", req.Addr.String()) + tconn, err := Connect(req.Addr.String()) if err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 connect:", err) - } + glog.V(LWARNING).Infoln("socks5 connect:", err) rep := gosocks5.NewReply(gosocks5.HostUnreachable, nil) if err := rep.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 connect:", err) - } + glog.V(LWARNING).Infoln("socks5 connect:", err) } else { - if glog.V(LDEBUG) { - glog.Infoln(rep) - } + glog.V(LDEBUG).Infoln(rep) } return } @@ -209,43 +175,31 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn) { rep := gosocks5.NewReply(gosocks5.Succeeded, nil) if err := rep.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 connect:", err) - } + glog.V(LWARNING).Infoln("socks5 connect:", err) return } - if glog.V(LDEBUG) { - glog.Infoln(rep) - } + glog.V(LDEBUG).Infoln(rep) Transport(conn, tconn) case gosocks5.CmdBind: - if glog.V(LINFO) { - glog.Infoln("socks5 bind:", req.Addr) - } + glog.V(LINFO).Infoln(">>> socks5 bind:", req.Addr) + if len(forwardArgs) > 0 { forwardBind(req, conn) } else { serveBind(conn) } case gosocks5.CmdUdp: - if glog.V(LINFO) { - glog.Infoln("socks5 udp associate:", req.Addr) - } + glog.V(LINFO).Infoln(">>> socks5 udp associate:", req.Addr) uconn, err := net.ListenUDP("udp", nil) if err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 udp listen:", err) - } + glog.V(LWARNING).Infoln("socks5 udp listen:", err) + rep := gosocks5.NewReply(gosocks5.Failure, nil) if err := rep.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 udp listen:", err) - } + glog.V(LWARNING).Infoln("socks5 udp listen:", err) } else { - if glog.V(LDEBUG) { - glog.Infoln(rep) - } + glog.V(LDEBUG).Infoln(rep) } return } @@ -253,47 +207,166 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn) { addr := ToSocksAddr(uconn.LocalAddr()) addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) - if glog.V(LINFO) { - glog.Infoln("socks5 udp listen:", addr) - } + glog.V(LINFO).Infoln("socks5 udp listen:", addr) + rep := gosocks5.NewReply(gosocks5.Succeeded, addr) if err := rep.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 udp:", err) - } + glog.V(LWARNING).Infoln("socks5 udp:", err) return } else { - if glog.V(LDEBUG) { - glog.Infoln(rep) - } + glog.V(LDEBUG).Infoln(rep) } - //clientConn, dgram, err := createClientConn(conn, uconn) - _, dgram, err := createClientConn(conn, uconn) + cc, dgram, err := createClientConn(conn, uconn) if err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 udp:", err) - } + glog.V(LWARNING).Infoln("socks5 udp:", err) return } - if glog.V(LDEBUG) { - glog.Infof("[udp] length %d, to %s", len(dgram.Data), dgram.Header.Addr) + glog.V(LDEBUG).Infof("[udp] to %s, length %d", dgram.Header.Addr, len(dgram.Data)) + + raddr, err := net.ResolveUDPAddr("udp", dgram.Header.Addr.String()) + if err != nil { + glog.V(LWARNING).Infoln("socks5 udp:", err) + return + } + sc, err := createServerConn(uconn, raddr) + if err != nil { + glog.V(LWARNING).Infoln("socks5 udp:", err) + return } - //serverConn, err := createServerConn(uconn) - _, err = createServerConn(uconn) + if err = sc.WriteUDP(dgram); err != nil { + glog.V(LWARNING).Infoln("socks5 udp:", err) + return + } + dgram, err = sc.ReadUDP() if err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 udp forward:", err) - } + glog.V(LWARNING).Infoln("socks5 udp:", err) + return } + glog.V(LDEBUG).Infof("[udp] from %s, length %d", dgram.Header.Addr, len(dgram.Data)) + + if err = cc.WriteUDP(dgram); err != nil { + glog.V(LWARNING).Infoln("socks5 udp:", err) + return + } + + TransportUDP(cc, sc) default: - if glog.V(LWARNING) { - glog.Warningln("Unrecognized request: ", req) - } + glog.V(LWARNING).Infoln("Unrecognized request: ", req) } } +func serveBind(conn net.Conn) error { + l, err := net.ListenTCP("tcp", nil) + if err != nil { + glog.V(LWARNING).Infoln("socks5 bind listen:", err) + + rep := gosocks5.NewReply(gosocks5.Failure, nil) + if err := rep.Write(conn); err != nil { + glog.V(LWARNING).Infoln("socks5 bind listen:", err) + } else { + glog.V(LDEBUG).Infoln(rep) + } + return err + } + + addr := ToSocksAddr(l.Addr()) + // Issue: may not reachable when host has two interfaces + addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) + glog.V(LINFO).Infoln("socks5 bind:", addr) + + rep := gosocks5.NewReply(gosocks5.Succeeded, addr) + if err := rep.Write(conn); err != nil { + glog.V(LWARNING).Infoln("socks5 bind:", err) + l.Close() + return err + } + glog.V(LDEBUG).Infoln(rep) + + tconn, err := l.AcceptTCP() + l.Close() // only accept one peer + if err != nil { + glog.V(LWARNING).Infoln("socks5 bind accept:", err) + + rep = gosocks5.NewReply(gosocks5.Failure, nil) + if err := rep.Write(conn); err != nil { + glog.V(LWARNING).Infoln("socks5 bind accept:", err) + } else { + glog.V(LDEBUG).Infoln(rep) + } + return err + } + defer tconn.Close() + + addr = ToSocksAddr(tconn.RemoteAddr()) + glog.V(LINFO).Infoln("socks5 bind accept:", addr.String()) + + rep = gosocks5.NewReply(gosocks5.Succeeded, addr) + if err := rep.Write(conn); err != nil { + glog.V(LWARNING).Infoln("socks5 bind accept:", err) + return err + } + glog.V(LDEBUG).Infoln(rep) + + return Transport(conn, tconn) +} + +func forwardBind(req *gosocks5.Request, conn net.Conn) error { + fconn, _, err := forwardChain(forwardArgs...) + if err != nil { + if fconn != nil { + fconn.Close() + } + rep := gosocks5.NewReply(gosocks5.Failure, nil) + if err := rep.Write(conn); err != nil { + glog.V(LWARNING).Infoln("socks5 bind forward:", err) + } else { + glog.V(LDEBUG).Infoln(rep) + } + return err + } + defer fconn.Close() + + if err := req.Write(fconn); err != nil { + glog.V(LWARNING).Infoln("socks5 bind forward:", err) + gosocks5.NewReply(gosocks5.Failure, nil).Write(conn) + return err + } + glog.V(LDEBUG).Infoln(req) + + // first reply + if err := peekReply(conn, fconn); err != nil { + glog.V(LWARNING).Infoln("socks5 bind forward:", err) + return err + } + // second reply + if err := peekReply(conn, fconn); err != nil { + glog.V(LWARNING).Infoln("socks5 bind forward:", err) + return err + } + + return Transport(conn, fconn) +} + +func peekReply(dst io.Writer, src io.Reader) error { + rep, err := gosocks5.ReadReply(src) + if err != nil { + glog.V(LWARNING).Infoln(err) + rep = gosocks5.NewReply(gosocks5.Failure, nil) + } + if err := rep.Write(dst); err != nil { + return err + } + glog.V(LDEBUG).Infoln(rep) + + if rep.Rep != gosocks5.Succeeded { + return errors.New("Failure") + } + + return nil +} + 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) @@ -338,7 +411,7 @@ func createClientConn(conn net.Conn, uconn *net.UDPConn) (c *UDPConn, dgram *gos return } -func createServerConn(uconn *net.UDPConn) (c *UDPConn, err error) { +func createServerConn(uconn *net.UDPConn, addr net.Addr) (c *UDPConn, err error) { if len(forwardArgs) == 0 { c = Server(uconn) return @@ -351,291 +424,30 @@ func createServerConn(uconn *net.UDPConn) (c *UDPConn, err error) { } return } + glog.V(LINFO).Infoln("forward udp associate") + + req := gosocks5.NewRequest(gosocks5.CmdUdp, nil) + if err = req.Write(fconn); err != nil { + fconn.Close() + return + } + glog.V(LDEBUG).Infoln(req) + + rep, err := gosocks5.ReadReply(fconn) + if err != nil { + fconn.Close() + return + } + glog.V(LDEBUG).Infoln(rep) + if rep.Rep != gosocks5.Succeeded { + fconn.Close() + return nil, errors.New("Failure") + } c = Server(fconn) return } -/* -func forwardUDP(req *gosocks5.Request) (conn net.Conn, err error) { - - if err != nil { - if conn != nil { - conn.Close() - } - rep := gosocks5.NewReply(gosocks5.Failure, nil) - if err := rep.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 udp forward:", err) - } - } else { - if glog.V(LDEBUG) { - glog.Infoln(rep) - } - } - return - } - - if err = req.Write(fconn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 udp forward:", err) - } - return - } - - if err = peekReply(conn, fconn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 udp forward:", err) - } - return - } - -} -*/ -func serveBind(conn net.Conn) error { - l, err := net.ListenTCP("tcp", nil) - if err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 bind listen:", err) - } - rep := gosocks5.NewReply(gosocks5.Failure, nil) - if err := rep.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 bind listen:", err) - } - } else { - if glog.V(LDEBUG) { - glog.Infoln(rep) - } - } - return err - } - - addr := ToSocksAddr(l.Addr()) - // Issue: may not reachable when host has two interfaces - addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) - if glog.V(LINFO) { - glog.Infoln("socks5 bind:", addr) - } - rep := gosocks5.NewReply(gosocks5.Succeeded, addr) - if err := rep.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 bind:", err) - } - l.Close() - return err - } - if glog.V(LDEBUG) { - glog.Infoln(rep) - } - - tconn, err := l.AcceptTCP() - l.Close() // only accept one peer - if err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 bind accept:", err) - } - rep = gosocks5.NewReply(gosocks5.Failure, nil) - if err := rep.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 bind accept:", err) - } - } else { - if glog.V(LDEBUG) { - glog.Infoln(rep) - } - } - return err - } - defer tconn.Close() - - addr = ToSocksAddr(tconn.RemoteAddr()) - if glog.V(LINFO) { - glog.Infoln("socks5 bind accept:", addr.String()) - } - rep = gosocks5.NewReply(gosocks5.Succeeded, addr) - if err := rep.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 bind accept:", err) - } - return err - } - if glog.V(LDEBUG) { - glog.Infoln(rep) - } - - return Transport(conn, tconn) -} - -func forwardBind(req *gosocks5.Request, conn net.Conn) error { - fconn, _, err := forwardChain(forwardArgs...) - if err != nil { - if fconn != nil { - fconn.Close() - } - rep := gosocks5.NewReply(gosocks5.Failure, nil) - if err := rep.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 bind forward:", err) - } - } else { - if glog.V(LDEBUG) { - glog.Infoln(rep) - } - } - return err - } - defer fconn.Close() - - if err := req.Write(fconn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 bind forward:", err) - } - gosocks5.NewReply(gosocks5.Failure, nil).Write(conn) - return err - } - if glog.V(LDEBUG) { - glog.Infoln(req) - } - - // first reply - if err := peekReply(conn, fconn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 bind forward:", err) - } - return err - } - // second reply - if err := peekReply(conn, fconn); err != nil { - if glog.V(LWARNING) { - glog.Warningln("socks5 bind forward:", err) - } - return err - } - - return Transport(conn, fconn) -} - -func peekReply(dst io.Writer, src io.Reader) error { - rep, err := gosocks5.ReadReply(src) - if err != nil { - if glog.V(LWARNING) { - glog.Warningln(err) - } - rep = gosocks5.NewReply(gosocks5.Failure, nil) - } - if err := rep.Write(dst); err != nil { - return err - } - if glog.V(LDEBUG) { - glog.Infoln(rep) - } - if rep.Rep != gosocks5.Succeeded { - return errors.New("Failure") - } - - return nil -} - -/* -func cliTunnelUDP(uconn *net.UDPConn, sconn net.Conn) { - var raddr *net.UDPAddr - - go func() { - b := make([]byte, 16*1024) - for { - n, addr, err := uconn.ReadFromUDP(b) - if err != nil { - log.Println(err) - return - } - raddr = addr - r := bytes.NewBuffer(b[:n]) - udp, err := gosocks5.ReadUDPDatagram(r) - if err != nil { - return - } - udp.Header.Rsv = uint16(len(udp.Data)) - //log.Println("r", raddr.String(), udp.Header) - - if err := udp.Write(sconn); err != nil { - log.Println(err) - return - } - } - }() - - for { - b := lpool.Take() - defer lpool.put(b) - - udp, err := gosocks5.ReadUDPDatagram(sconn) - if err != nil { - log.Println(err) - return - } - //log.Println("w", udp.Header) - udp.Header.Rsv = 0 - buf := bytes.NewBuffer(b[0:0]) - udp.Write(buf) - if _, err := uconn.WriteTo(buf.Bytes(), raddr); err != nil { - log.Println(err) - return - } - } -} - -func srvTunnelUDP(conn net.Conn, uconn *net.UDPConn) { - go func() { - b := make([]byte, 16*1024) - - for { - n, addr, err := uconn.ReadFromUDP(b) - if err != nil { - if glog.V(LWARNING) { - glog.Warningln(err) - } - return - } - - udp := gosocks5.NewUDPDatagram( - gosocks5.NewUDPHeader(uint16(n), 0, ToSocksAddr(addr)), b[:n]) - //log.Println("r", udp.Header) - if err := udp.Write(conn); err != nil { - if glog.V(LWARNING) { - glog.Warningln(err) - } - return - } - } - }() - - for { - udp, err := gosocks5.ReadUDPDatagram(conn) - if err != nil { - if glog.V(LWARNING) { - glog.Warningln(err) - } - return - } - //log.Println("w", udp.Header) - addr, err := net.ResolveUDPAddr("udp", udp.Header.Addr.String()) - if err != nil { - if glog.V(LWARNING) { - glog.Warningln(err) - } - continue // drop silently - } - - if _, err := uconn.WriteToUDP(udp.Data, addr); err != nil { - if glog.V(LWARNING) { - glog.Warningln(err) - } - return - } - } -} -*/ func ToSocksAddr(addr net.Addr) *gosocks5.Addr { host, port, _ := net.SplitHostPort(addr.String()) p, _ := strconv.Atoi(port) @@ -646,3 +458,40 @@ func ToSocksAddr(addr net.Addr) *gosocks5.Addr { Port: uint16(p), } } + +func PipeUDP(src, dst *UDPConn, ch chan<- error) { + var err error + + for { + var dgram *gosocks5.UDPDatagram + 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.WriteUDP(dgram); err != nil { + break + } + } + + ch <- err + close(ch) +} + +func TransportUDP(cc, sc *UDPConn) (err error) { + rChan := make(chan error, 1) + wChan := make(chan error, 1) + + go PipeUDP(cc, sc, wChan) + go PipeUDP(sc, cc, rChan) + + select { + case err = <-wChan: + //log.Println("w exit", err) + case err = <-rChan: + //log.Println("r exit", err) + } + + return +} diff --git a/ss.go b/ss.go index c8560b2..4df16fd 100644 --- a/ss.go +++ b/ss.go @@ -16,9 +16,7 @@ func handleShadow(conn net.Conn, arg Args) { password, _ := arg.User.Password() cipher, err := shadowsocks.NewCipher(method, password) if err != nil { - if glog.V(LWARNING) { - glog.Warningln("shadowsocks:", err) - } + glog.V(LWARNING).Infoln("shadowsocks:", err) return } conn = shadowsocks.NewConn(conn, cipher) @@ -26,28 +24,21 @@ func handleShadow(conn net.Conn, arg Args) { addr, extra, err := getShadowRequest(conn) if err != nil { - if glog.V(LWARNING) { - glog.Warningln("shadowsocks:", err) - } + glog.V(LWARNING).Infoln("shadowsocks:", err) return } - if glog.V(LINFO) { - glog.Infoln("shadowsocks connect:", addr.String()) - } + glog.V(LINFO).Infoln("shadowsocks connect:", addr.String()) + sconn, err := Connect(addr.String()) if err != nil { - if glog.V(LWARNING) { - glog.Warningln("shadowsocks:", err) - } + glog.V(LWARNING).Infoln("shadowsocks:", err) return } defer sconn.Close() if extra != nil { if _, err := sconn.Write(extra); err != nil { - if glog.V(LWARNING) { - glog.Warningln("shadowsocks:", err) - } + glog.V(LWARNING).Infoln("shadowsocks:", err) return } } diff --git a/udp.go b/udp.go index aec31cd..eb53f49 100644 --- a/udp.go +++ b/udp.go @@ -1,39 +1,148 @@ package main import ( - //"github.com/ginuerzh/gosocks5" - //"github.com/golang/glog" + "bytes" + "github.com/ginuerzh/gosocks5" + "github.com/golang/glog" "net" + "time" ) type UDPConn struct { isClient bool - udpConn *net.UDPConn + udp *net.UDPConn addr net.Addr - tcpConn net.Conn + tcp net.Conn } func Client(conn net.Conn, addr net.Addr) *UDPConn { - client := &UDPConn{isClient: true} + c := &UDPConn{isClient: true} switch conn := conn.(type) { case *net.UDPConn: - client.udpConn = conn - client.addr = addr + c.udp = conn + c.addr = addr default: - client.tcpConn = conn + c.tcp = conn } - return client + return c } func Server(conn net.Conn) *UDPConn { - server := &UDPConn{} + c := &UDPConn{} + switch conn := conn.(type) { case *net.UDPConn: - server.udpConn = conn + c.udp = conn default: - server.tcpConn = conn + c.tcp = conn } - return server + + return c +} + +func (c *UDPConn) ReadUDP() (*gosocks5.UDPDatagram, error) { + if c.isClient { + return c.readUDPClient() + } + return c.readUDPServer() +} + +func (c *UDPConn) readUDPClient() (*gosocks5.UDPDatagram, error) { + if c.udp != nil { + return gosocks5.ReadUDPDatagram(c.udp) + } + return gosocks5.ReadUDPDatagram(c.tcp) +} + +func (c *UDPConn) readUDPServer() (*gosocks5.UDPDatagram, error) { + if c.udp != nil { + b := make([]byte, 65535) + n, addr, err := c.udp.ReadFromUDP(b) + if err != nil { + return nil, err + } + dgram := gosocks5.NewUDPDatagram( + gosocks5.NewUDPHeader(0, 0, ToSocksAddr(addr)), b[:n]) + return dgram, nil + } + + return gosocks5.ReadUDPDatagram(c.tcp) +} + +func (c *UDPConn) WriteUDP(dgram *gosocks5.UDPDatagram) error { + if c.isClient { + return c.writeUDPClient(dgram) + } + return c.writeUDPServer(dgram) +} + +func (c *UDPConn) writeUDPClient(dgram *gosocks5.UDPDatagram) error { + if c.udp != nil { + dgram.Header.Rsv = 0 + buffer := bytes.Buffer{} + dgram.Write(&buffer) + _, err := c.udp.WriteTo(buffer.Bytes(), c.addr) + return err + } + + dgram.Header.Rsv = uint16(len(dgram.Data)) + return dgram.Write(c.tcp) +} + +func (c *UDPConn) writeUDPServer(dgram *gosocks5.UDPDatagram) error { + if c.udp != nil { + addr, err := net.ResolveUDPAddr("udp", dgram.Header.Addr.String()) + if err != nil { + glog.V(LWARNING).Infoln(err) + return nil // drop silently + } + _, err = c.udp.WriteTo(dgram.Data, addr) + return err + } + dgram.Header.Rsv = uint16(len(dgram.Data)) + return dgram.Write(c.tcp) +} + +func (c *UDPConn) Close() error { + if c.udp != nil { + return c.udp.Close() + } + return c.tcp.Close() +} + +func (c *UDPConn) LocalAddr() net.Addr { + if c.udp != nil { + return c.udp.LocalAddr() + } + return c.tcp.LocalAddr() +} + +func (c *UDPConn) RemoteAddr() net.Addr { + if c.udp != nil { + return c.udp.RemoteAddr() + } + return c.tcp.RemoteAddr() +} + +func (c *UDPConn) SetDeadline(t time.Time) error { + if c.udp != nil { + return c.udp.SetDeadline(t) + } + return c.tcp.SetDeadline(t) +} + +func (c *UDPConn) SetReadDeadline(t time.Time) error { + if c.udp != nil { + return c.udp.SetReadDeadline(t) + } + return c.tcp.SetReadDeadline(t) +} + +func (c *UDPConn) SetWriteDeadline(t time.Time) error { + if c.udp != nil { + return c.udp.SetWriteDeadline(t) + } + return c.tcp.SetWriteDeadline(t) } diff --git a/util.go b/util.go index 732222e..570dbea 100644 --- a/util.go +++ b/util.go @@ -62,12 +62,11 @@ nh/BAoGBAMY5z2f1pmMhrvtPDSlEVjgjELbaInxFaxPLR4Pdyzn83gtIIU14+R8X func init() { var err error if cert, err = tls.LoadX509KeyPair("cert.pem", "key.pem"); err != nil { - if glog.V(LFATAL) { - glog.Warningln(err) - } + glog.V(LWARNING).Infoln(err) + cert, err = tls.X509KeyPair([]byte(rawCert), []byte(rawKey)) - if err != nil && glog.V(LFATAL) { - glog.Warningln(err) + if err != nil { + glog.V(LFATAL).Infoln(err) } } } @@ -112,9 +111,7 @@ func parseArgs(ss []string) (args []Args) { } u, err := url.Parse(s) if err != nil { - if glog.V(LWARNING) { - glog.Warningln(err) - } + glog.V(LWARNING).Infoln(err) continue } @@ -186,9 +183,9 @@ func Copy(dst io.Writer, src io.Reader) (written int64, err error) { return } -func Pipe(src io.Reader, dst io.Writer, c chan<- error) { +func Pipe(src io.Reader, dst io.Writer, ch chan<- error) { _, err := Copy(dst, src) - c <- err + ch <- err } func Transport(conn, conn2 net.Conn) (err error) { diff --git a/ws.go b/ws.go index cffd357..bc1a0b8 100644 --- a/ws.go +++ b/ws.go @@ -105,9 +105,7 @@ func (s *ws) handle(w http.ResponseWriter, r *http.Request) { } conn, err := s.upgrader.Upgrade(w, r, nil) if err != nil { - if glog.V(LERROR) { - glog.Errorln(err) - } + glog.V(LERROR).Infoln(err) return } handleConn(wsServer(conn), s.arg)