func parseServerConfig(config *ss.Config) { if len(config.ServerPassword) == 0 { // only one encryption table cipher, err := ss.NewCipher(config.Method, config.Password) if err != nil { log.Fatal("Failed generating ciphers:", err) } srvPort := strconv.Itoa(config.ServerPort) srvArr := config.GetServerArray() n := len(srvArr) servers.srvCipher = make([]*ServerCipher, n) for i, s := range srvArr { if ss.HasPort(s) { log.Println("ignore server_port option for server", s) servers.srvCipher[i] = &ServerCipher{s, cipher} } else { servers.srvCipher[i] = &ServerCipher{s + ":" + srvPort, cipher} } } } else { // multiple servers n := len(config.ServerPassword) servers.srvCipher = make([]*ServerCipher, n) cipherCache := make(map[string]ss.Cipher) i := 0 for _, serverInfo := range config.ServerPassword { if len(serverInfo) < 2 || len(serverInfo) > 3 { log.Fatalf("server %v syntax error\n", serverInfo) } server := serverInfo[0] passwd := serverInfo[1] encmethod := "" if len(serverInfo) == 3 { encmethod = serverInfo[2] } if !ss.HasPort(server) { log.Fatalf("no port for server %s, please specify port in the form of %s:port\n", server, server) } cipher, ok := cipherCache[passwd] if !ok { var err error cipher, err = ss.NewCipher(encmethod, passwd) if err != nil { log.Fatal("Failed generating ciphers:", err) } cipherCache[passwd] = cipher } servers.srvCipher[i] = &ServerCipher{server, cipher} i++ } } servers.failCnt = make([]int, len(servers.srvCipher)) for _, se := range servers.srvCipher { log.Println("available remote server", se.server) } return }
func initServers(config *ss.Config) { if len(config.ServerPassword) == 0 { // only one encryption table cipher, err := ss.NewCipher(config.Password) if err != nil { log.Fatal("Failed generating ciphers:", err) } srvPort := strconv.Itoa(config.ServerPort) srvArr := config.GetServerArray() n := len(srvArr) servers.srvCipher = make([]*ServerCipher, n, n) for i, s := range srvArr { if ss.HasPort(s) { log.Println("ignore server_port option for server", s) servers.srvCipher[i] = &ServerCipher{s, cipher} } else { servers.srvCipher[i] = &ServerCipher{s + ":" + srvPort, cipher} } } } else { n := len(config.ServerPassword) servers.srvCipher = make([]*ServerCipher, n, n) cipherCache := make(map[string]ss.Cipher) i := 0 for s, passwd := range config.ServerPassword { if !ss.HasPort(s) { log.Fatal("no port for server %s, please specify port in the form of %s:port", s, s) } cipher, ok := cipherCache[passwd] if !ok { var err error cipher, err = ss.NewCipher(passwd) if err != nil { log.Fatal("Failed generating ciphers:", err) } cipherCache[passwd] = cipher } servers.srvCipher[i] = &ServerCipher{s, cipher} i++ } } for _, se := range servers.srvCipher { log.Println("available remote server", se.server) } return }
func clientMethodSelected(method uint8, conn net.Conn) (net.Conn, error) { switch method { case gosocks5.MethodUserPass: user, pass := parseUserPass(Password) if err := clientSocksAuth(conn, user, pass); err != nil { return nil, err } case MethodTLS, MethodTLSAuth: conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true}) if method == MethodTLSAuth { if len(Password) == 0 { return nil, ErrEmptyAuth } if err := clientSocksAuth(conn, "", Password); err != nil { return nil, err } } case MethodAES128, MethodAES192, MethodAES256, MethodDES, MethodBF, MethodCAST5, MethodRC4MD5, MethodRC4, MethodTable: cipher, err := shadowsocks.NewCipher(Methods[method], Password) if err != nil { log.Println(err) return nil, err } conn = shadowsocks.NewConn(conn, cipher) case gosocks5.MethodNoAcceptable: return nil, gosocks5.ErrBadMethod } return conn, nil }
func serverMethodSelected(method uint8, conn net.Conn) (net.Conn, error) { switch method { case MethodTLS: var cert tls.Certificate var err error if len(CertFile) == 0 || len(KeyFile) == 0 { cert, err = tls.X509KeyPair([]byte(rawCert), []byte(rawKey)) } else { cert, err = tls.LoadX509KeyPair(CertFile, KeyFile) } if err != nil { return nil, err } conn = tls.Server(conn, &tls.Config{Certificates: []tls.Certificate{cert}}) if err := svrTLSAuth(conn); err != nil { return nil, err } case MethodAES128, MethodAES192, MethodAES256, MethodDES, MethodBF, MethodCAST5, MethodRC4MD5, MethodRC4, MethodTable: cipher, err := shadowsocks.NewCipher(Methods[method], Password) if err != nil { return nil, err } conn = shadowsocks.NewConn(conn, cipher) case gosocks5.MethodNoAcceptable: return nil, gosocks5.ErrBadMethod } return conn, nil }
func handleShadow(conn net.Conn, arg Args) { if arg.User != nil { method := arg.User.Username() password, _ := arg.User.Password() cipher, err := shadowsocks.NewCipher(method, password) if err != nil { glog.V(LWARNING).Infoln("shadowsocks:", err) return } conn = shadowsocks.NewConn(conn, cipher) } addr, extra, err := getShadowRequest(conn) if err != nil { glog.V(LWARNING).Infoln("shadowsocks:", err) return } glog.V(LINFO).Infoln("shadowsocks connect:", addr.String()) sconn, err := Connect(addr.String()) if err != nil { glog.V(LWARNING).Infoln("shadowsocks:", err) return } defer sconn.Close() if extra != nil { if _, err := sconn.Write(extra); err != nil { glog.V(LWARNING).Infoln("shadowsocks:", err) return } } Transport(conn, sconn) }
func run(port, password string) { ln, err := net.Listen("tcp", ":"+port) if err != nil { log.Printf("error listening port %v: %v\n", port, err) return } passwdManager.add(port, password, ln) var cipher *ss.Cipher log.Printf("server listening port %v ...\n", port) for { conn, err := ln.Accept() if err != nil { // listener maybe closed to update password debug.Printf("accept error: %v\n", err) return } // Creating cipher upon first connection. if cipher == nil { log.Println("creating cipher for port:", port) cipher, err = ss.NewCipher(config.Method, password) if err != nil { log.Printf("Error generating cipher for port: %s %v\n", port, err) conn.Close() continue } } go handleConnection(ss.NewConn(conn, cipher.Copy())) } }
func (sp *shadowsocksParent) initCipher(passwd, method string) { cipher, err := ss.NewCipher(method, passwd) if err != nil { Fatal("creating shadowsocks cipher:", err) } sp.cipher = cipher }
func runWithCustomMethod(user user.User) { // port, password string, Cipher *ss.Cipher port := strconv.Itoa(user.GetPort()) password := user.GetPasswd() ln, err := net.Listen("tcp", ":"+port) if err != nil { Log.Error(fmt.Sprintf("error listening port %v: %v\n", port, err)) os.Exit(1) } passwdManager.add(port, password, ln) cipher, err := user.GetCipher() if err != nil { return } Log.Info(fmt.Sprintf("server listening port %v ...\n", port)) for { conn, err := ln.Accept() if err != nil { // listener maybe closed to update password Log.Debug(fmt.Sprintf("accept error: %v\n", err)) return } // Creating cipher upon first connection. if cipher == nil { Log.Debug("creating cipher for port:", port) cipher, err = ss.NewCipher(user.GetMethod(), password) if err != nil { Log.Error(fmt.Sprintf("Error generating cipher for port: %s %v\n", port, err)) conn.Close() continue } } go handleConnection(user, ss.NewConn(conn, cipher.Copy())) } }
func newMeowProxy(method, passwd, addr string) *meowProxy { cipher, err := ss.NewCipher(method, passwd) if err != nil { Fatal("can't initialize meow proxy server", err) } return &meowProxy{addr, method, passwd, cipher} }
func newCowParent(srv, method, passwd string) *cowParent { cipher, err := ss.NewCipher(method, passwd) if err != nil { Fatal("create cow cipher:", err) } return &cowParent{srv, method, passwd, cipher} }
func (sp *shadowsocksParent) initCipher(method, passwd string) { sp.method = method sp.passwd = passwd cipher, err := ss.NewCipher(method, passwd) if err != nil { Fatal("create shadowsocks cipher:", err) } sp.cipher = cipher }
func init() { proxyTransports["http"] = func(proxyURL *url.URL) (*http.Transport, error) { return &http.Transport{ Proxy: func(req *http.Request) (*url.URL, error) { return proxyURL, nil }, }, nil } proxyTransports["socks5"] = func(proxyURL *url.URL) (*http.Transport, error) { ph, err := proxy.FromURL(proxyURL, proxy.Direct) if err != nil { return nil, err } return &http.Transport{ Dial: ph.Dial, }, nil } proxyTransports["socks4"] = func(proxyURL *url.URL) (*http.Transport, error) { dialSocksProxy := socks.DialSocksProxy(socks.SOCKS4A, proxyURL.Host) return &http.Transport{ Dial: dialSocksProxy, }, nil } proxyTransports["socks4a"] = func(proxyURL *url.URL) (*http.Transport, error) { dialSocksProxy := socks.DialSocksProxy(socks.SOCKS4A, proxyURL.Host) return &http.Transport{ Dial: dialSocksProxy, }, nil } //shadowsocks proxyTransports["ss"] = func(proxyURL *url.URL) (*http.Transport, error) { if proxyURL.User == nil { return nil, fmt.Errorf("wrong shadowsocks uri,need method and passwd") } psw, _ := proxyURL.User.Password() cipher, err := ss.NewCipher(proxyURL.User.Username(), psw) if err != nil { return nil, err } serverAddr := proxyURL.Host return &http.Transport{ Dial: func(_, addr string) (net.Conn, error) { return ss.Dial(addr, serverAddr, cipher.Copy()) }, // DialTLS:func(_, addr string) (net.Conn, error) { // return ss.Dial(addr, serverAddr, cipher.Copy()) // }, }, nil } }
func forward(conn net.Conn, arg Args) (net.Conn, error) { var err error if glog.V(LINFO) { proto := arg.Protocol if proto == "default" { proto = "http" // default is http } glog.Infof("forward: %s/%s %s", proto, arg.Transport, arg.Addr) } switch arg.Transport { case "ws": // websocket connection conn, err = wsClient(conn, arg.Addr) if err != nil { return nil, err } case "tls": // tls connection conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true}) case "tcp": fallthrough default: } switch arg.Protocol { case "socks", "socks5": selector := &clientSelector{ methods: []uint8{ gosocks5.MethodNoAuth, gosocks5.MethodUserPass, MethodTLS, }, arg: arg, } c := gosocks5.ClientConn(conn, selector) if err := c.Handleshake(); err != nil { return nil, err } conn = c case "ss": // shadowsocks if arg.User != nil { method := arg.User.Username() password, _ := arg.User.Password() cipher, err := shadowsocks.NewCipher(method, password) if err != nil { return nil, err } conn = shadowsocks.NewConn(conn, cipher) } case "http": fallthrough default: } return conn, nil }
func (u User) GetCipher() (*ss.Cipher, error, bool) { method := u.Method auth := false if strings.HasSuffix(method, "-auth") { method = method[:len(method)-5] auth = true } s, e := ss.NewCipher(method, u.Passwd) return s, e, auth }
func (s *SSDialer) Dial(network, addr string) (c net.Conn, err error) { cipher, err := ss.NewCipher(s.Method, s.Password) if err != nil { return nil, err } ssConn, err := ss.Dial(addr, s.Host, cipher) if err != nil { return nil, err } return ssConn, nil }
func (sp *shadowsocksParent) initCipher(method, passwd string) error { if method == "table" { method = "" } sp.method = method sp.passwd = passwd cipher, err := ss.NewCipher(method, passwd) if err != nil { return err } sp.cipher = cipher return nil }
func New(conf *ProxyConfig) (ps *ProxyServer, err error) { ps = &ProxyServer{ config: conf, joins: make(chan net.Conn), stop: make(chan bool), Stopped: true, } ps.Cip, err = ss.NewCipher(conf.Method, conf.EncrStr) if err != nil { err = errors.Newf("create cipher error: %v", err) } return }
func runWithCustomMethod(user user.User) { // port, password string, Cipher *ss.Cipher port := strconv.Itoa(user.GetPort()) // 检测端口是否已存在 _, ok := passwdManager.get(port) // 如果存在 if ok { return } password := user.GetPasswd() ln, err := net.Listen("tcp", ":"+port) if err != nil { Log.Error(fmt.Sprintf("error listening port %v: %v\n", port, err)) // os.Exit(1) return } passwdManager.add(port, password, ln) cipher, err, auth := user.GetCipher() if err != nil { return } Log.Info(fmt.Sprintf("server listening port %v ...\n", port)) for { conn, err := ln.Accept() if err != nil { // listener maybe closed to update password Log.Debug(fmt.Sprintf("accept error: %v\n", err)) return } // Creating cipher upon first connection. if cipher == nil { Log.Debug("creating cipher for port:", port) method := user.GetMethod() if strings.HasSuffix(method, "-auth") { method = method[:len(method)-5] auth = true } else { auth = false } cipher, err = ss.NewCipher(method, password) if err != nil { Log.Error(fmt.Sprintf("Error generating cipher for port: %s %v\n", port, err)) conn.Close() continue } } go handleConnection(user, ss.NewConn(conn, cipher.Copy()), auth) } }
func serverMethodSelected(method uint8, conn net.Conn) (net.Conn, error) { //log.Println(method) switch method { case gosocks5.MethodUserPass: var username, password string if listenUrl != nil && listenUrl.User != nil { username = listenUrl.User.Username() password, _ = listenUrl.User.Password() } if err := serverSocksAuth(conn, username, password); err != nil { return nil, err } case MethodTLS, MethodTLSAuth: var cert tls.Certificate var err error if len(CertFile) == 0 || len(KeyFile) == 0 { cert, err = tls.X509KeyPair([]byte(rawCert), []byte(rawKey)) } else { cert, err = tls.LoadX509KeyPair(CertFile, KeyFile) } if err != nil { return nil, err } conn = tls.Server(conn, &tls.Config{Certificates: []tls.Certificate{cert}}) if method == MethodTLSAuth { // password is mandatory if len(Password) == 0 { return nil, ErrEmptyAuth } if err := serverSocksAuth(conn, "", Password); err != nil { return nil, err } } case MethodAES128, MethodAES192, MethodAES256, MethodDES, MethodBF, MethodCAST5, MethodRC4MD5, MethodRC4, MethodTable: cipher, err := shadowsocks.NewCipher(Methods[method], Password) if err != nil { return nil, err } conn = shadowsocks.NewConn(conn, cipher) case gosocks5.MethodNoAcceptable: return nil, gosocks5.ErrBadMethod } return conn, nil }
func runUDP(port string, password [3]string) { addr, _ := net.ResolveUDPAddr(netUdp, ":"+port) conn, err := net.ListenUDP(netUdp, addr) if err != nil { log.Printf("error listening udp port %v: %v\n", port, err) return } passwdManager.addUDP(port, password, conn) log.Printf("server listening udp port %v ...\n", port) defer conn.Close() var cipher *ss.Cipher cipher, err = ss.NewCipher(config.Method, password[0]) if err != nil { log.Printf("Error generating cipher for udp port: %s %v\n", port, err) conn.Close() } ss.HandleUDPConnection(ss.NewUDPConn(conn, cipher.Copy()), password[1]) }
func run(port, password string) { var addr string var lastTime int64 ln, err := net.Listen("tcp", ":"+port) if err != nil { log.Printf("error listening port %v: %v\n", port, err) return } passwdManager.add(port, password, ln) var cipher *ss.Cipher log.Printf("server listening port %v ...\n", port) for { conn, err := ln.Accept() if err != nil { // listener maybe closed to update password debug.Printf("accept error: %v\n", err) return } newaddr := conn.RemoteAddr().String() nowtime := time.Now().Unix() if addr != newaddr && lastTime >= nowtime { conn.Close() continue } lastTime = nowtime addr = newaddr // Creating cipher upon first connection. if cipher == nil { log.Println("creating cipher for port:", port) cipher, err = ss.NewCipher(config.Method, password) if err != nil { log.Printf("Error generating cipher for port: %s %v\n", port, err) conn.Close() continue } } go handleConnection(ss.NewConn(conn, cipher.Copy())) } }
func initShadowSocks() { if config.ShadowSocks != "" && config.ShadowPasswd != "" { var err error if err = ss.SetDefaultCipher(config.ShadowMethod); err != nil { fmt.Println("Initializing shadowsocks:", err) os.Exit(1) } if cipher, err = ss.NewCipher(config.ShadowPasswd); err != nil { fmt.Println("Creating shadowsocks cipher:", err) os.Exit(1) } debug.Println("shadowsocks server:", config.ShadowSocks) return } if (config.ShadowSocks != "" && config.ShadowPasswd == "") || (config.ShadowSocks == "" && config.ShadowPasswd != "") { fmt.Println("Missing option: shadowSocks and shadowPasswd should be both given") os.Exit(1) } }
func initShadowSocks() { // error checking is done when parsing config if len(config.ShadowSocks) == 0 { return } for i, _ := range config.ShadowSocks { // initialize cipher for each shadowsocks connection if c, err := ss.NewCipher(config.ShadowMethod[i], config.ShadowPasswd[i]); err != nil { Fatal("creating shadowsocks cipher:", err) } else { cipher = append(cipher, c) } if debug { if config.ShadowMethod[i] != "" { debug.Println("shadowsocks server:", config.ShadowSocks[i], "encryption:", config.ShadowMethod[i]) } else { debug.Println("shadowsocks server:", config.ShadowSocks[i]) } } } }
func TestShadowsocksTCP(t *testing.T) { v2testing.Current(t) tcpServer := &tcp.Server{ Port: v2net.Port(50052), MsgProcessor: func(data []byte) []byte { buffer := make([]byte, 0, 2048) buffer = append(buffer, []byte("Processed: ")...) buffer = append(buffer, data...) return buffer }, } _, err := tcpServer.Start() assert.Error(err).IsNil() defer tcpServer.Close() assert.Error(InitializeServerServer("test_6")).IsNil() cipher, err := ssclient.NewCipher("aes-256-cfb", "v2ray-password") assert.Error(err).IsNil() rawAddr := []byte{1, 127, 0, 0, 1, 0xc3, 0x84} // 127.0.0.1:50052 conn, err := ssclient.DialWithRawAddr(rawAddr, "127.0.0.1:50051", cipher) assert.Error(err).IsNil() payload := "shadowsocks request." nBytes, err := conn.Write([]byte(payload)) assert.Error(err).IsNil() assert.Int(nBytes).Equals(len(payload)) conn.Conn.(*net.TCPConn).CloseWrite() response := make([]byte, 1024) nBytes, err = conn.Read(response) assert.Error(err).IsNil() assert.StringLiteral("Processed: " + payload).Equals(string(response[:nBytes])) conn.Close() CloseAllServers() }
func cliHandle(conn net.Conn) { defer conn.Close() if Shadows { cipher, _ := shadowsocks.NewCipher(SMethod, SPassword) conn = shadowsocks.NewConn(conn, cipher) handleShadow(conn) return } b := mpool.Take() defer mpool.put(b) n, err := io.ReadAtLeast(conn, b, 2) if err != nil { return } if b[0] == gosocks5.Ver5 { mn := int(b[1]) // methods count length := 2 + mn if n < length { if _, err := io.ReadFull(conn, b[n:length]); err != nil { return } } methods := b[2 : 2+mn] handleSocks5(conn, methods) return } req, err := http.ReadRequest(bufio.NewReader(newReqReader(b[:n], conn))) if err != nil { //log.Println(hex.Dump(b[:n])) log.Println(err) return } handleHttp(req, conn) }
func run(port string) { ln, err := net.Listen("tcp", ":"+port) if err != nil { log.Printf("error listening port %v: %v\n", port, err) os.Exit(0) } var cipher *ss.Cipher log.Printf("server listening port %v ...\n", port) for { conn, err := ln.Accept() if err != nil { log.Printf("accept error: %v\n", err) continue } user, err := getUser(conn) if err != nil { log.Printf("Error get passeoed: %s %v\n", port, err) conn.Close() continue } size, err := storage.GetSize("flow:" + user.Name) if user.Limit < size { log.Printf("Error user runover: %s\n", size) conn.Close() continue } // log.Println("creating cipher for user:"******"Error generating cipher for user: %s %v\n", user.Name, err) conn.Close() continue } go handleConnection(user, ss.NewConn(conn, cipher.Copy())) } }
func newSsProxyClient(proxyAddr, method, password string, upProxy ProxyClient, query map[string][]string) (ProxyClient, error) { p := ssProxyClient{} cipher, err := ss.NewCipher(method, password) if err != nil { return nil, fmt.Errorf("创建代理错误:%v", err) } if upProxy == nil { nUpProxy, err := newDriectProxyClient("", false, 0, make(map[string][]string)) if err != nil { return nil, fmt.Errorf("创建直连代理错误:%v", err) } upProxy = nUpProxy } p.proxyAddr = proxyAddr p.cipher = cipher p.upProxy = upProxy p.query = query return &p, nil }
func NewProxyServer(node ProxyNode, chain *ProxyChain, config *tls.Config) *ProxyServer { if chain == nil { chain = NewProxyChain() } if config == nil { config = &tls.Config{} } var cipher *ss.Cipher if node.Protocol == "ss" && node.User != nil { var err error method := node.User.Username() password, _ := node.User.Password() cipher, err = ss.NewCipher(method, password) if err != nil { glog.Fatal(err) } } return &ProxyServer{ Node: node, Chain: chain, TLSConfig: config, selector: &serverSelector{ // socks5 server selector // methods that socks5 server supported methods: []uint8{ gosocks5.MethodNoAuth, gosocks5.MethodUserPass, MethodTLS, MethodTLSAuth, }, user: node.User, tlsConfig: config, }, cipher: cipher, } }
func parseServerConfig(config *ss.Config) { hasPort := func(s string) bool { _, port, err := net.SplitHostPort(s) if err != nil { return false } return port != "" } if len(config.ServerPassword) == 0 { method := config.Method if config.Auth { method += "-ota" } // only one encryption table cipher, err := ss.NewCipher(method, config.Password) if err != nil { log.Fatal("Failed generating ciphers:", err) } srvPort := strconv.Itoa(config.ServerPort) srvArr := config.GetServerArray() n := len(srvArr) servers.srvCipher = make([]*ServerCipher, n) for i, s := range srvArr { if hasPort(s) { log.Println("ignore server_port option for server", s) servers.srvCipher[i] = &ServerCipher{s, cipher} } else { servers.srvCipher[i] = &ServerCipher{net.JoinHostPort(s, srvPort), cipher} } } } else { // multiple servers n := len(config.ServerPassword) servers.srvCipher = make([]*ServerCipher, n) cipherCache := make(map[string]*ss.Cipher) i := 0 for _, serverInfo := range config.ServerPassword { if len(serverInfo) < 2 || len(serverInfo) > 3 { log.Fatalf("server %v syntax error\n", serverInfo) } server := serverInfo[0] passwd := serverInfo[1] encmethod := "" if len(serverInfo) == 3 { encmethod = serverInfo[2] } if !hasPort(server) { log.Fatalf("no port for server %s\n", server) } // Using "|" as delimiter is safe here, since no encryption // method contains it in the name. cacheKey := encmethod + "|" + passwd cipher, ok := cipherCache[cacheKey] if !ok { var err error cipher, err = ss.NewCipher(encmethod, passwd) if err != nil { log.Fatal("Failed generating ciphers:", err) } cipherCache[cacheKey] = cipher } servers.srvCipher[i] = &ServerCipher{server, cipher} i++ } } servers.failCnt = make([]int, len(servers.srvCipher)) for _, se := range servers.srvCipher { log.Println("available remote server", se.server) } return }
func TestSsProxy(t *testing.T) { // 测试域名 testAddr := "www.test123.com:80" testData := []byte("dsgbhdfhgsq36jhrawdxghucn46ggetst") testServerAddr := "127.0.0.1:1458" testMethod := "aes-256-cfb" testPassword := "******" testRawAddr, err := ss.RawAddr(testAddr) if err != nil { t.Fatal(err) } // 简单模拟服务器 cipher, err := ss.NewCipher(testMethod, testPassword) if err != nil { t.Fatal(err) } l, err := net.Listen("tcp", testServerAddr) if err != nil { t.Fatal(err) } defer l.Close() go func() { c, err := l.Accept() if err != nil { t.Fatal(err) } c.SetDeadline(time.Now().Add(5 * time.Second)) sc := ss.NewConn(c, cipher) defer sc.Close() // 读内容并返回 for i := 0; i < 2; i++ { buf := make([]byte, 1024) if n, err := sc.Read(buf); err != nil { t.Fatal("i=", i, "服务器读内容错误:", err) } else { if _, err := sc.Write(buf[:n]); err != nil { t.Fatal(err) } } } }() // 发出请求,然后解密。 p, err := newSsProxyClient(testServerAddr, testMethod, testPassword, nil, nil) if err != nil { t.Fatal(err) } c, err := p.DialTimeout("tcp", testAddr, 1*time.Second) if err != nil { t.Fatal(err) } defer c.Close() // 比较地址是否正确 buf := make([]byte, 1024) if n, err := c.Read(buf); err != nil { t.Fatal("读地址错误:", err) } else { if bytes.Compare(buf[:n], testRawAddr) != 0 { t.Fatal("地址未正确发送") } } // 发送测试数据,并读取比较 if _, err := c.Write(testData); err != nil { t.Fatal(err) } if n, err := c.Read(buf); err != nil { t.Fatal(err) } else { if bytes.Compare(buf[:n], testData) != 0 { t.Fatal("数据未正确发送") } } }