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)