package gost import ( //"bytes" "crypto/tls" //"errors" "github.com/ginuerzh/gosocks5" "github.com/golang/glog" //"os/exec" //"io" //"io/ioutil" "net" "net/url" //"strconv" //"time" ) const ( MethodTLS uint8 = 0x80 // extended method for tls MethodTLSAuth uint8 = 0x82 // extended method for tls+auth ) const ( CmdUdpConnect uint8 = 0xF1 // extended method for udp local port forwarding CmdUdpTun uint8 = 0xF3 // extended method for udp over tcp ) type clientSelector struct { methods []uint8 user *url.Userinfo } func (selector *clientSelector) Methods() []uint8 { return selector.methods } func (selector *clientSelector) Select(methods ...uint8) (method uint8) { return } func (selector *clientSelector) OnSelected(method uint8, conn net.Conn) (net.Conn, error) { switch method { case MethodTLS: conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true}) case gosocks5.MethodUserPass, MethodTLSAuth: if method == MethodTLSAuth { conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true}) } var username, password string if selector.user != nil { username = selector.user.Username() password, _ = selector.user.Password() } req := gosocks5.NewUserPassRequest(gosocks5.UserPassVer, username, password) if err := req.Write(conn); err != nil { glog.V(LWARNING).Infoln("socks5 auth:", err) return nil, err } glog.V(LDEBUG).Infoln(req) resp, err := gosocks5.ReadUserPassResponse(conn) if err != nil { glog.V(LWARNING).Infoln("socks5 auth:", err) return nil, err } glog.V(LDEBUG).Infoln(resp) if resp.Status != gosocks5.Succeeded { return nil, gosocks5.ErrAuthFailure } case gosocks5.MethodNoAcceptable: return nil, gosocks5.ErrBadMethod } return conn, nil } type serverSelector struct { methods []uint8 user *url.Userinfo cert tls.Certificate } func (selector *serverSelector) Methods() []uint8 { return selector.methods } func (selector *serverSelector) Select(methods ...uint8) (method uint8) { glog.V(LDEBUG).Infof("%d %d %v", gosocks5.Ver5, len(methods), methods) method = gosocks5.MethodNoAuth for _, m := range methods { if m == MethodTLS { method = m break } } // when user/pass is set, auth is mandatory if selector.user != nil { if method == gosocks5.MethodNoAuth { method = gosocks5.MethodUserPass } if method == MethodTLS { method = MethodTLSAuth } } return } func (selector *serverSelector) OnSelected(method uint8, conn net.Conn) (net.Conn, error) { glog.V(LDEBUG).Infof("%d %d", gosocks5.Ver5, method) switch method { case MethodTLS: conn = tls.Server(conn, &tls.Config{Certificates: []tls.Certificate{selector.cert}}) case gosocks5.MethodUserPass, MethodTLSAuth: if method == MethodTLSAuth { conn = tls.Server(conn, &tls.Config{Certificates: []tls.Certificate{selector.cert}}) } req, err := gosocks5.ReadUserPassRequest(conn) if err != nil { glog.V(LWARNING).Infoln("[socks5-auth]", err) return nil, err } glog.V(LDEBUG).Infoln("[socks5]", req.String()) var username, password string if selector.user != nil { username = selector.user.Username() password, _ = selector.user.Password() } if (username != "" && req.Username != username) || (password != "" && req.Password != password) { resp := gosocks5.NewUserPassResponse(gosocks5.UserPassVer, gosocks5.Failure) if err := resp.Write(conn); err != nil { glog.V(LWARNING).Infoln("[socks5-auth]", err) return nil, err } glog.V(LDEBUG).Infoln("[socks5]", resp) glog.V(LWARNING).Infoln("[socks5-auth] proxy authentication required") return nil, gosocks5.ErrAuthFailure } resp := gosocks5.NewUserPassResponse(gosocks5.UserPassVer, gosocks5.Succeeded) if err := resp.Write(conn); err != nil { glog.V(LWARNING).Infoln("[socks5-auth]", err) return nil, err } glog.V(LDEBUG).Infoln(resp) case gosocks5.MethodNoAcceptable: return nil, gosocks5.ErrBadMethod } return conn, nil }