From 573d31ae23963f3dc8a4c3d47ba7dfb728c2a4e9 Mon Sep 17 00:00:00 2001 From: "rui.zheng" Date: Wed, 10 Jun 2015 14:26:41 +0800 Subject: [PATCH] add new cipher method tls-auth --- README.md | 19 ++++++++---- client.go | 86 +++++++++++++++++++++++++++++++++--------------------- http.go | 2 +- main.go | 26 ----------------- socks5.go | 18 ++++++++---- util.go | 15 ++++++++++ version.go | 2 +- ws.go | 2 +- 8 files changed, 97 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 12efa48..0df2fae 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,12 @@ gost - GO Simple Tunnel Google讨论组: https://groups.google.com/d/forum/go-gost #### 版本更新 +##### v1.6 +* 增加tls-auth加密方式,此方式必须设置认证密码(-p参数),原tls加密方式与v1.3版以前兼容 + +###### Bug fix: +* 修正当不设置上层代理时,连接出错问题 + ##### v1.5 * 支持设置上层socks5代理(注: http tunnel不支持) * 支持上层代理用户名密码验证 @@ -110,7 +116,7 @@ gost支持作为shadowsocks服务器运行(-ss参数),这样就可以让androi #### tunnel加密说明 ##### 目前支持的加密方法 -tls, aes-128-cfb, aes-192-cfb, aes-256-cfb, des-cfb, bf-cfb, cast5-cfb, rc4-md5, rc4, table +tls, tls-auth, aes-128-cfb, aes-192-cfb, aes-256-cfb, des-cfb, bf-cfb, cast5-cfb, rc4-md5, rc4, table ##### Client @@ -118,7 +124,7 @@ Client端通过-m参数设置加密方式,默认为不加密(-m参数为空) 如果设置的加密方式不被支持,则默认为不加密。 -当设置的加密方式为tls时,可通过-p参数设置验证密码(若服务端支持密码验证功能)。 +当设置的加密方式为tls时,-p参数无效。 当设置的加密方式为非tls时,通过-p参数设置加密密码,且不能为空;-p参数必须与Server端的-p参数相同。 @@ -132,7 +138,10 @@ Server端通过-m参数设置加密方式,默认为不加密(-m参数为空) 如果设置了加密方式(-m参数不为空),client端必须使用与Server端相同的加密方式。 -当设置的加密方式为tls时,-key参数可手动指定公钥文件,-cert参数可手动指定私钥文件,如果未指定,则使用默认的公钥与私钥。 -可通过-p参数设定验证密码(可选),若设置,则客户端必须通过-p参数设置相同的密码。 +当设置的加密方式为tls,tls-auth时,-key参数可手动指定公钥文件,-cert参数可手动指定私钥文件,如果未指定,则使用默认的公钥与私钥。 + +当设置的加密方式为tls时,-p参数无效;为tls-auth时,通过-p参数设置认证密码,且不能为空。 + +当设置的加密方式为非tls,tls-auth时,-key,-cert参数无效;通过-p参数设置加密密码,且不能为空。 + -当设置的加密方式为非tls时,-key,-cert参数无效;通过-p参数设置加密密码,且不能为空。 diff --git a/client.go b/client.go index 98d7e02..64f00e7 100644 --- a/client.go +++ b/client.go @@ -58,10 +58,12 @@ func listenAndServe(addr string, handler func(net.Conn)) error { func clientMethodSelected(method uint8, conn net.Conn) (net.Conn, error) { switch method { - case MethodTLS: + case MethodTLS, MethodTLSAuth: conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true}) - if err := cliTLSAuth(conn); err != nil { - return nil, err + if method == MethodTLSAuth { + if err := cliTLSAuth(conn); err != nil { + return nil, err + } } case MethodAES128, MethodAES192, MethodAES256, MethodDES, MethodBF, MethodCAST5, MethodRC4MD5, MethodRC4, MethodTable: @@ -79,6 +81,10 @@ func clientMethodSelected(method uint8, conn net.Conn) (net.Conn, error) { } func cliTLSAuth(conn net.Conn) error { + if len(Password) == 0 { + return ErrEmptyPassword + } + if err := gosocks5.NewUserPassRequest( gosocks5.UserPassVer, "", Password).Write(conn); err != nil { return err @@ -94,19 +100,7 @@ func cliTLSAuth(conn net.Conn) error { return nil } -func cliHandle(conn net.Conn) { - defer conn.Close() - /* - fmt.Println("new session", atomic.AddInt64(&sessionCount, 1)) - defer func() { - fmt.Println("session end", atomic.AddInt64(&sessionCount, -1)) - }() - */ - - //log.Println("connect:", Saddr, Proxy) - var c net.Conn - var err error - +func makeTunnel() (c net.Conn, err error) { if UseWebsocket || !UseHttp { c, err = connect(Saddr) } else { @@ -117,40 +111,44 @@ func cliHandle(conn net.Conn) { c, err = dial(addr) } if err != nil { - log.Println(err) return } - defer c.Close() - if UseWebsocket { ws, resp, err := websocket.NewClient(c, &url.URL{Host: Saddr}, nil, 8192, 8192) if err != nil { - log.Println(err) - return + c.Close() + return nil, err } resp.Body.Close() c = NewWSConn(ws) } else if UseHttp { httpcli := NewHttpClientConn(c) - if err := httpcli.Handshake(); err != nil { - log.Println(err) - return + if err = httpcli.Handshake(); err != nil { + c.Close() + return nil, err } c = httpcli - defer httpcli.Close() + //defer httpcli.Close() } sc := gosocks5.ClientConn(c, clientConfig) - if err := sc.Handleshake(); err != nil { - return + if err = sc.Handleshake(); err != nil { + c.Close() + return nil, err } c = sc + return +} + +func cliHandle(conn net.Conn) { + defer conn.Close() + if Shadows { cipher, _ := shadowsocks.NewCipher(SMethod, SPassword) conn = shadowsocks.NewConn(conn, cipher) - handleShadow(conn, c) + handleShadow(conn) return } @@ -174,7 +172,7 @@ func cliHandle(conn net.Conn) { return } - handleSocks5(conn, c) + handleSocks5(conn) return } @@ -196,15 +194,22 @@ func cliHandle(conn net.Conn) { log.Println(err) return } - handleHttp(req, conn, c) + handleHttp(req, conn) } -func handleSocks5(conn net.Conn, sconn net.Conn) { +func handleSocks5(conn net.Conn) { req, err := gosocks5.ReadRequest(conn) if err != nil { return } + //log.Println(req) + sconn, err := makeTunnel() + if err != nil { + gosocks5.NewReply(gosocks5.Failure, nil).Write(conn) + log.Println(err) + return + } switch req.Cmd { case gosocks5.CmdConnect, gosocks5.CmdBind: @@ -295,7 +300,7 @@ func cliTunnelUDP(uconn *net.UDPConn, sconn net.Conn) { } } -func handleHttp(req *http.Request, conn net.Conn, sconn net.Conn) { +func handleHttp(req *http.Request, conn net.Conn) { var host string var port uint16 @@ -313,6 +318,15 @@ func handleHttp(req *http.Request, conn net.Conn, sconn net.Conn) { Port: port, } r := gosocks5.NewRequest(gosocks5.CmdConnect, addr) + + sconn, err := makeTunnel() + if err != nil { + conn.Write([]byte("HTTP/1.1 503 Service unavailable\r\n" + + "Proxy-Agent: gost/" + Version + "\r\n\r\n")) + log.Println(err) + return + } + if err := r.Write(sconn); err != nil { return } @@ -340,13 +354,19 @@ func handleHttp(req *http.Request, conn net.Conn, sconn net.Conn) { } } -func handleShadow(conn, sconn net.Conn) { +func handleShadow(conn net.Conn) { addr, extra, err := getShadowRequest(conn) if err != nil { log.Println(err) return } + sconn, err := makeTunnel() + if err != nil { + log.Println(err) + return + } + req := gosocks5.NewRequest(gosocks5.CmdConnect, addr) if err := req.Write(sconn); err != nil { log.Println(err) diff --git a/http.go b/http.go index 8e41c51..2f33035 100644 --- a/http.go +++ b/http.go @@ -219,7 +219,7 @@ func (s *HttpServer) s2c(w http.ResponseWriter, r *http.Request) { s.conns[token] = conn defer delete(s.conns, token) - socks5Handle(gosocks5.ServerConn(conn, serverConfig)) + serveSocks5(gosocks5.ServerConn(conn, serverConfig)) } func (s *HttpServer) c2s(w http.ResponseWriter, r *http.Request) { diff --git a/main.go b/main.go index 3b0d5fb..41643c6 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,6 @@ import ( //"github.com/ginuerzh/gosocks5" "log" "net/url" - "strings" "time" ) @@ -18,10 +17,8 @@ var ( Method, Password string CertFile, KeyFile string PrintVersion bool - Filter string proxyURL *url.URL - filters []string ) func init() { @@ -37,14 +34,12 @@ func init() { flag.BoolVar(&UseHttp, "http", false, "use http tunnel") flag.StringVar(&SMethod, "sm", "rc4-md5", "shadowsocks cipher method") flag.StringVar(&SPassword, "sp", "ginuerzh@gmail.com", "shadowsocks cipher password") - flag.StringVar(&Filter, "f", "", "comma separated host/url wildcard not go through tunnel") flag.BoolVar(&PrintVersion, "v", false, "print version") flag.Parse() log.SetFlags(log.LstdFlags | log.Lshortfile) proxyURL, _ = parseURL(Proxy) - filters = parseFilter(Filter) } var ( @@ -74,24 +69,3 @@ func main() { log.Fatal(listenAndServe(Laddr, cliHandle)) } - -func parseURL(rawurl string) (*url.URL, error) { - if len(rawurl) == 0 { - return nil, nil - } - if !strings.HasPrefix(rawurl, "http://") && - !strings.HasPrefix(rawurl, "socks://") { - rawurl = "http://" + rawurl - } - return url.Parse(rawurl) -} - -func parseFilter(rawfilter string) (filters []string) { - for _, s := range strings.Split(rawfilter, ",") { - s = strings.TrimSpace(s) - if len(s) > 0 { - filters = append(filters) - } - } - return -} diff --git a/socks5.go b/socks5.go index 6249aa0..342ccf4 100644 --- a/socks5.go +++ b/socks5.go @@ -89,7 +89,7 @@ func (s *Socks5Server) ListenAndServe() error { } //log.Println("accept", conn.RemoteAddr()) - go socks5Handle(gosocks5.ServerConn(conn, serverConfig)) + go serveSocks5(gosocks5.ServerConn(conn, serverConfig)) } } @@ -111,7 +111,7 @@ func serverSelectMethod(methods ...uint8) uint8 { func serverMethodSelected(method uint8, conn net.Conn) (net.Conn, error) { switch method { - case MethodTLS: + case MethodTLS, MethodTLSAuth: var cert tls.Certificate var err error @@ -125,8 +125,10 @@ func serverMethodSelected(method uint8, conn net.Conn) (net.Conn, error) { return nil, err } conn = tls.Server(conn, &tls.Config{Certificates: []tls.Certificate{cert}}) - if err := svrTLSAuth(conn); err != nil { - return nil, err + if method == MethodTLSAuth { + if err := svrTLSAuth(conn); err != nil { + return nil, err + } } case MethodAES128, MethodAES192, MethodAES256, MethodDES, MethodBF, MethodCAST5, MethodRC4MD5, MethodRC4, MethodTable: @@ -143,12 +145,16 @@ func serverMethodSelected(method uint8, conn net.Conn) (net.Conn, error) { } func svrTLSAuth(conn net.Conn) error { + if len(Password) == 0 { + return ErrEmptyPassword + } + req, err := gosocks5.ReadUserPassRequest(conn) if err != nil { return err } - if len(Password) > 0 && req.Password != Password { + if req.Password != Password { if err := gosocks5.NewUserPassResponse( gosocks5.UserPassVer, gosocks5.Failure).Write(conn); err != nil { return err @@ -164,7 +170,7 @@ func svrTLSAuth(conn net.Conn) error { return nil } -func socks5Handle(conn net.Conn) { +func serveSocks5(conn net.Conn) { defer conn.Close() req, err := gosocks5.ReadRequest(conn) diff --git a/util.go b/util.go index 2023a27..543b674 100644 --- a/util.go +++ b/util.go @@ -26,8 +26,11 @@ const ( MethodRC4MD5 MethodRC4 MethodTable + MethodTLSAuth ) +var ErrEmptyPassword = errors.New("empty key") + var Methods = map[uint8]string{ gosocks5.MethodNoAuth: "", // 0x00 MethodTLS: "tls", // 0x80 @@ -40,6 +43,18 @@ var Methods = map[uint8]string{ MethodRC4MD5: "rc4-md5", // 8x87 MethodRC4: "rc4", // 0x88 MethodTable: "table", // 0x89 + MethodTLSAuth: "tls-auth", // 0x90 +} + +func parseURL(rawurl string) (*url.URL, error) { + if len(rawurl) == 0 { + return nil, nil + } + if !strings.HasPrefix(rawurl, "http://") && + !strings.HasPrefix(rawurl, "socks://") { + rawurl = "http://" + rawurl + } + return url.Parse(rawurl) } func ToSocksAddr(addr net.Addr) *gosocks5.Addr { diff --git a/version.go b/version.go index 1f1157b..3215dcf 100644 --- a/version.go +++ b/version.go @@ -5,7 +5,7 @@ import ( ) const ( - Version = "1.5" + Version = "1.6" ) func printVersion() { diff --git a/ws.go b/ws.go index 14d698a..e8e6d2d 100644 --- a/ws.go +++ b/ws.go @@ -73,7 +73,7 @@ func (s *WSServer) handle(w http.ResponseWriter, r *http.Request) { return } */ - socks5Handle(c) + serveSocks5(c) } func (s *WSServer) ListenAndServe() error {