From 5804c14367ea856fbdb1b927b7c87bef149bcff9 Mon Sep 17 00:00:00 2001 From: Hadi Zo Date: Sun, 30 Oct 2022 12:57:27 -0400 Subject: [PATCH 1/2] Add command line client with SOCKS --- cmd/client/client.go | 216 +++++++++++++++++++++++++++++++++ cmd/client/client_test.go | 249 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 465 insertions(+) create mode 100644 cmd/client/client.go create mode 100644 cmd/client/client_test.go diff --git a/cmd/client/client.go b/cmd/client/client.go new file mode 100644 index 00000000..90a98d59 --- /dev/null +++ b/cmd/client/client.go @@ -0,0 +1,216 @@ +// Copyright 2022 Jigsaw Operations LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "bytes" + "encoding/base64" + "errors" + "flag" + "fmt" + "net" + "net/url" + "os" + "os/signal" + "strconv" + "strings" + "syscall" + + "github.com/Jigsaw-Code/outline-ss-server/client" + onet "github.com/Jigsaw-Code/outline-ss-server/net" + "github.com/op/go-logging" + "github.com/shadowsocks/go-shadowsocks2/socks" + "golang.org/x/crypto/ssh/terminal" +) + +var logger *logging.Logger + +func init() { + var prefix = "%{level:.1s}%{time:2006-01-02T15:04:05.000Z07:00} %{pid} %{shortfile}]" + if terminal.IsTerminal(int(os.Stderr.Fd())) { + // Add color only if the output is the terminal + prefix = strings.Join([]string{"%{color}", prefix, "%{color:reset}"}, "") + } + logging.SetFormatter(logging.MustStringFormatter(strings.Join([]string{prefix, " %{message}"}, ""))) + logging.SetBackend(logging.NewLogBackend(os.Stderr, "", 0)) + logger = logging.MustGetLogger("") +} + +type serverConfig struct { + host string + port int + cipher string + secret string +} + +func parseKey(k string) (serverConfig, error) { + u, err := url.Parse(k) + if err != nil { + return serverConfig{}, err + } + + port, err := strconv.Atoi(u.Port()) + if err != nil { + return serverConfig{}, fmt.Errorf("invalid port: %v", err) + } + + secret := u.User.String() + if !strings.Contains(secret, ":") { + b, err := base64.StdEncoding.DecodeString(secret) + if err != nil { + b, err = base64.RawStdEncoding.DecodeString(u.User.String()) + if err != nil { + return serverConfig{}, fmt.Errorf("invalid password in key: %v", err) + } + } + secret = string(bytes.TrimSpace(b)) + } + p := strings.Split(secret, ":") + if len(p) != 2 { + return serverConfig{}, fmt.Errorf("invalid password in key") + } + + return serverConfig{ + host: u.Hostname(), + port: port, + cipher: p[0], + secret: p[1], + }, nil +} + +func resolveHostPort(addr string) (string, error) { + host, port, err := net.SplitHostPort(addr) + if err != nil { + return "", err + } + ip, err := net.ResolveIPAddr("ip", host) + if err != nil { + return "", fmt.Errorf("resolving hostname failed: %v", err) + } + return net.JoinHostPort(ip.String(), port), err +} + +type SocksSSClient struct { + config serverConfig + listener *net.TCPListener +} + +// RunSocksSSClient starts a SOCKS server which proxies connections to the specified shadowsocks server. +func RunSocksSSClient(bindAddr string, listenPort int, config serverConfig) (*SocksSSClient, error) { + listener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP(bindAddr), Port: listenPort}) + if err != nil { + return nil, fmt.Errorf("listenTCP failed: %v", err) + } + logger.Infof("Listenting at %v", listener.Addr()) + + d, err := client.NewClient(config.host, config.port, config.secret, config.cipher) + if err != nil { + return nil, fmt.Errorf("failed connecting to server: %v", err) + } + + go func() { + for { + clientConn, err := listener.AcceptTCP() + if err != nil { + if errors.Is(err, net.ErrClosed) { + logger.Info("SOCKS listener closed") + } else { + logger.Errorf("Accepting SOCKS connection failed: %v\n", err) + } + break + } + go func() { + defer clientConn.Close() + + tgtAddr, err := socks.Handshake(clientConn) + if err != nil { + logger.Errorf("SOCKS handshake failed: %v", err) + return + } + addr, err := resolveHostPort(tgtAddr.String()) + if err != nil { + logger.Errorf("Failed to resolve target address: %v", err) + return + } + + logger.Debugf("Opening connection for %s", addr) + targetConn, err := d.DialTCP(nil, addr) + if err != nil { + logger.Errorf("Failed to dial: %v", err) + return + } + defer targetConn.Close() + _, _, err = onet.Relay(clientConn, targetConn) + if err != nil { + logger.Errorf("Relay failed: %v", err) + return + } + logger.Debugf("Connection closed %s", addr) + }() + } + }() + return &SocksSSClient{listener: listener}, nil +} + +// ListenAddr returns the listening address used by the SOCKS server +func (s *SocksSSClient) ListenAddr() net.Addr { + return s.listener.Addr() +} + +// Stop stops the SOCKS server +func (s *SocksSSClient) Stop() error { + return s.listener.Close() +} + +func main() { + var flags struct { + BindAddr string + ListenPort int + ServerKey string + Verbose bool + } + + flag.StringVar(&flags.BindAddr, "bind", "127.0.0.1", "") + flag.IntVar(&flags.ListenPort, "port", 1080, "") + flag.StringVar(&flags.ServerKey, "key", "", "") + flag.BoolVar(&flags.Verbose, "verbose", false, "Enables verbose logging output") + + flag.Parse() + + if flags.Verbose { + logging.SetLevel(logging.DEBUG, "") + } else { + logging.SetLevel(logging.INFO, "") + } + + if flags.ServerKey == "" { + flag.Usage() + return + } + + sc, err := parseKey(flags.ServerKey) + if err != nil { + logger.Fatalf("Invalid key: %v", err) + } + + _, err = RunSocksSSClient(flags.BindAddr, flags.ListenPort, sc) + if err != nil { + logger.Fatalf("Failed running client: %v", err) + } + + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) + <-sigCh +} diff --git a/cmd/client/client_test.go b/cmd/client/client_test.go new file mode 100644 index 00000000..1708afb5 --- /dev/null +++ b/cmd/client/client_test.go @@ -0,0 +1,249 @@ +// Copyright 2022 Jigsaw Operations LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "bytes" + "container/list" + "fmt" + "io" + "net" + "reflect" + "strconv" + "testing" + "time" + + onet "github.com/Jigsaw-Code/outline-ss-server/net" + "github.com/Jigsaw-Code/outline-ss-server/service" + "github.com/Jigsaw-Code/outline-ss-server/service/metrics" + ss "github.com/Jigsaw-Code/outline-ss-server/shadowsocks" + "github.com/prometheus/client_golang/prometheus" +) + +const ( + testSecret = "secret" +) + +func TestParseKey(t *testing.T) { + testCases := []struct { + name string + key string + want serverConfig + wantErr bool + }{ + { + name: "with b64 padding", + key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpteXBhc3N3b3JkCg==@127.0.0.1:9000/", + want: serverConfig{host: "127.0.0.1", port: 9000, cipher: "chacha20-ietf-poly1305", secret: "mypassword"}, + }, + { + name: "without b64 padding", + key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpteXBhc3N3b3JkCg@1.2.3.4:8080", + want: serverConfig{host: "1.2.3.4", port: 8080, cipher: "chacha20-ietf-poly1305", secret: "mypassword"}, + }, + { + name: "without b64", + key: "ss://chacha20-ietf-poly1305:mypassword@1.2.3.4:9000/", + want: serverConfig{host: "1.2.3.4", port: 9000, cipher: "chacha20-ietf-poly1305", secret: "mypassword"}, + }, + { + name: "with tag", + key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpteXBhc3N3b3JkCg@1.2.3.4:8080#TAG", + want: serverConfig{host: "1.2.3.4", port: 8080, cipher: "chacha20-ietf-poly1305", secret: "mypassword"}, + }, + { + name: "fail on no secret", + key: "ss://1.2.3.4:8080", + wantErr: true, + }, + { + name: "fail on no port", + key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpteXBhc3N3b3JkCg@1.2.3.4#TAG", + wantErr: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got, err := parseKey(tc.key) + if err != nil { + if !tc.wantErr { + t.Errorf("parseKey('%s') got unexpected error: %v", tc.key, err) + } + } else if !reflect.DeepEqual(got, tc.want) { + t.Errorf("parseKey('%s') got=%v want=%v", tc.key, got, tc.want) + } + }) + } +} + +func TestSSSocksClient(t *testing.T) { + ssSrvListener, ssSrv := startSSServer(t) + defer ssSrv.Stop() + + echoListener, echoCloseCh := startEchoServer(t) + defer echoListener.Close() + + ssCli, err := RunSocksSSClient("127.0.0.1", 0, serverConfig{ + host: "127.0.0.1", + port: addrPort(t, ssSrvListener.Addr()), + cipher: ss.TestCipher, + secret: testSecret, + }) + if err != nil { + t.Fatalf("Running client failed: %v", err) + } + defer ssCli.Stop() + + socksCon := dialSocks(t, addrPort(t, ssCli.ListenAddr()), addrPort(t, echoListener.Addr())) + payload := ss.MakeTestPayload(1024) + _, err = socksCon.Write(payload) + if err != nil { + t.Fatalf("Writing to SOCKS connection failed: %v", err) + } + + buf := make([]byte, 2048) + n, err := socksCon.Read(buf) + if err != nil { + t.Fatalf("Reading from SOCKS connection failed: %v", err) + } + + // Check received payload matches sent payload + if bytes.Compare(buf[:n], payload) != 0 { + t.Fatalf("Wrong data recevied, expected=%v got=%v", payload, buf) + } + + // Check that target connection closes after closing SOCKS connection + select { + case <-echoCloseCh: + t.Fatalf("SSServer<->EchoServer connection closed before SOCKS connection") + default: + } + socksCon.Close() + select { + case <-time.After(50 * time.Millisecond): + t.Fatalf("SSServer<->EchoServer connection not closed after SOCKS connection closed") + case <-echoCloseCh: + } +} + +func startSSServer(t *testing.T) (net.Listener, service.TCPService) { + cipher, err := ss.NewCipher(ss.TestCipher, testSecret) + if err != nil { + t.Fatalf("failed to create cipher: %v", err) + } + entry := service.MakeCipherEntry("tst-cipher", cipher, testSecret) + cipherList := *&list.List{} + cipherList.PushBack(&entry) + ciphers := service.NewCipherList() + ciphers.Update(&cipherList) + + rc := service.NewReplayCache(2) + tcpsvc := service.NewTCPService( + ciphers, + &rc, + metrics.NewPrometheusShadowsocksMetrics(nil, prometheus.DefaultRegisterer), + 59*time.Second, + ) + tcpsvc.SetTargetIPValidator(func(i net.IP) *onet.ConnectionError { + return nil + }) + + l, err := net.ListenTCP("tcp", nil) + if err != nil { + t.Fatalf("Failed to start TCP listen: %v", err) + } + + go tcpsvc.Serve(l) + return l, tcpsvc +} + +func startEchoServer(t *testing.T) (net.Listener, chan struct{}) { + l, err := net.ListenTCP("tcp", nil) + if err != nil { + t.Fatalf("Failed to start TCP listen: %v", err) + } + closeCh := make(chan struct{}) + go func() { + c, err := l.Accept() + if err != nil { + t.Fatalf("Accepting connection failed: %v\n", err) + return + } + _, err = io.Copy(c, c) + if err != nil { + t.Fatalf(err.Error()) + } + close(closeCh) + }() + return l, closeCh +} + +func dialSocks(t *testing.T, socksPort int, targetPort int) (_ net.Conn) { + conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", socksPort)) + if err != nil { + t.Fatalf("Connecting to SOCKS server failed: %v", err) + } + + conn.Write([]byte{ + byte(5), // version + 1, // number of methods + byte(0), // method - no auth + }) + + b := make([]byte, 128) + n, err := conn.Read(b) + if err != nil { + t.Fatalf("SOCKS negotiation failed: %v", err) + } else if n != 2 { + t.Fatalf("SOCKS initial server reply invalid, expected 2 bytes got=%d", n) + } else if b[0] != 5 { + t.Fatalf("SOCKS 5 not supported") + } else if b[1] != 0 { + t.Fatalf("SOCKS method negotiation failed, expected=0 got=%d", b[1]) + } + + conn.Write([]byte{ + byte(5), // version + 1, // connect command + 0, // reserved + 1, // address type - ip + 127, 0, 0, 1, // ip + byte(targetPort >> 8), + byte(targetPort), + }) + + n, err = conn.Read(b) + if err != nil { + t.Fatalf("SOCKS request failed: %v", err) + } else if n != 10 { + t.Fatalf("SOCKS server invalid response, expected 10 bytes got=%d", n) + } else if b[1] != 0 { + t.Fatalf("SOCKS server failed") + } + return conn +} + +func addrPort(t *testing.T, a net.Addr) int { + _, p, err := net.SplitHostPort(a.String()) + if err != nil { + t.Fatalf(err.Error()) + } + port, err := strconv.Atoi(p) + if err != nil { + t.Fatalf(err.Error()) + } + return port +} From 908969cb06f4fa099bfb34d34a9e1701c918206f Mon Sep 17 00:00:00 2001 From: Hadi Zo Date: Mon, 31 Oct 2022 11:35:18 -0400 Subject: [PATCH 2/2] Renames and cleaning up based on review comments --- cmd/client/{client.go => socks2ss.go} | 86 ++++++++----------- .../{client_test.go => socks2ss_test.go} | 34 ++++---- 2 files changed, 54 insertions(+), 66 deletions(-) rename cmd/client/{client.go => socks2ss.go} (64%) rename cmd/client/{client_test.go => socks2ss_test.go} (83%) diff --git a/cmd/client/client.go b/cmd/client/socks2ss.go similarity index 64% rename from cmd/client/client.go rename to cmd/client/socks2ss.go index 90a98d59..59642f63 100644 --- a/cmd/client/client.go +++ b/cmd/client/socks2ss.go @@ -15,7 +15,6 @@ package main import ( - "bytes" "encoding/base64" "errors" "flag" @@ -48,41 +47,46 @@ func init() { logger = logging.MustGetLogger("") } -type serverConfig struct { +type sessionConfig struct { host string port int cipher string secret string } -func parseKey(k string) (serverConfig, error) { +func parseAccessKey(k string) (sessionConfig, error) { u, err := url.Parse(k) if err != nil { - return serverConfig{}, err + return sessionConfig{}, err } port, err := strconv.Atoi(u.Port()) if err != nil { - return serverConfig{}, fmt.Errorf("invalid port: %v", err) + return sessionConfig{}, fmt.Errorf("invalid port: %v", err) } - secret := u.User.String() - if !strings.Contains(secret, ":") { - b, err := base64.StdEncoding.DecodeString(secret) + cipherAndSecret := u.User.String() + + // If we see a ":" in the string, assume its not base64 encoded and skip decoding + if !strings.Contains(cipherAndSecret, ":") { + // Attempt to decode with padding + b, err := base64.StdEncoding.DecodeString(cipherAndSecret) if err != nil { - b, err = base64.RawStdEncoding.DecodeString(u.User.String()) + // Attempt to decode without padding + b, err = base64.RawStdEncoding.DecodeString(cipherAndSecret) if err != nil { - return serverConfig{}, fmt.Errorf("invalid password in key: %v", err) + return sessionConfig{}, fmt.Errorf("invalid password in key: %v", err) } } - secret = string(bytes.TrimSpace(b)) + cipherAndSecret = string(b) } - p := strings.Split(secret, ":") + + p := strings.Split(cipherAndSecret, ":") if len(p) != 2 { - return serverConfig{}, fmt.Errorf("invalid password in key") + return sessionConfig{}, fmt.Errorf("invalid password in key") } - return serverConfig{ + return sessionConfig{ host: u.Hostname(), port: port, cipher: p[0], @@ -90,32 +94,20 @@ func parseKey(k string) (serverConfig, error) { }, nil } -func resolveHostPort(addr string) (string, error) { - host, port, err := net.SplitHostPort(addr) - if err != nil { - return "", err - } - ip, err := net.ResolveIPAddr("ip", host) - if err != nil { - return "", fmt.Errorf("resolving hostname failed: %v", err) - } - return net.JoinHostPort(ip.String(), port), err -} - -type SocksSSClient struct { - config serverConfig +type SocksToSS struct { + config sessionConfig listener *net.TCPListener } -// RunSocksSSClient starts a SOCKS server which proxies connections to the specified shadowsocks server. -func RunSocksSSClient(bindAddr string, listenPort int, config serverConfig) (*SocksSSClient, error) { +// RunSocksToSS starts a SOCKS server which proxies connections to the specified shadowsocks server. +func RunSocksToSS(bindAddr string, listenPort int, config sessionConfig) (*SocksToSS, error) { listener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP(bindAddr), Port: listenPort}) if err != nil { return nil, fmt.Errorf("listenTCP failed: %v", err) } logger.Infof("Listenting at %v", listener.Addr()) - d, err := client.NewClient(config.host, config.port, config.secret, config.cipher) + ssClient, err := client.NewClient(config.host, config.port, config.secret, config.cipher) if err != nil { return nil, fmt.Errorf("failed connecting to server: %v", err) } @@ -139,14 +131,9 @@ func RunSocksSSClient(bindAddr string, listenPort int, config serverConfig) (*So logger.Errorf("SOCKS handshake failed: %v", err) return } - addr, err := resolveHostPort(tgtAddr.String()) - if err != nil { - logger.Errorf("Failed to resolve target address: %v", err) - return - } - logger.Debugf("Opening connection for %s", addr) - targetConn, err := d.DialTCP(nil, addr) + logger.Debugf("Opening connection for %s", tgtAddr) + targetConn, err := ssClient.DialTCP(nil, tgtAddr.String()) if err != nil { logger.Errorf("Failed to dial: %v", err) return @@ -157,20 +144,20 @@ func RunSocksSSClient(bindAddr string, listenPort int, config serverConfig) (*So logger.Errorf("Relay failed: %v", err) return } - logger.Debugf("Connection closed %s", addr) + logger.Debugf("Connection closed %s", tgtAddr) }() } }() - return &SocksSSClient{listener: listener}, nil + return &SocksToSS{listener: listener}, nil } // ListenAddr returns the listening address used by the SOCKS server -func (s *SocksSSClient) ListenAddr() net.Addr { +func (s *SocksToSS) ListenAddr() net.Addr { return s.listener.Addr() } // Stop stops the SOCKS server -func (s *SocksSSClient) Stop() error { +func (s *SocksToSS) Stop() error { return s.listener.Close() } @@ -178,13 +165,13 @@ func main() { var flags struct { BindAddr string ListenPort int - ServerKey string + AccessKey string Verbose bool } - flag.StringVar(&flags.BindAddr, "bind", "127.0.0.1", "") - flag.IntVar(&flags.ListenPort, "port", 1080, "") - flag.StringVar(&flags.ServerKey, "key", "", "") + flag.StringVar(&flags.BindAddr, "bind", "127.0.0.1", "Local address to bind to.") + flag.IntVar(&flags.ListenPort, "port", 1080, "Local port to listen on.") + flag.StringVar(&flags.AccessKey, "key", "", "Access key specifying how to connect to the server. Only ss:// links are accepted.") flag.BoolVar(&flags.Verbose, "verbose", false, "Enables verbose logging output") flag.Parse() @@ -195,17 +182,18 @@ func main() { logging.SetLevel(logging.INFO, "") } - if flags.ServerKey == "" { + if flags.AccessKey == "" { flag.Usage() return } - sc, err := parseKey(flags.ServerKey) + sc, err := parseAccessKey(flags.AccessKey) if err != nil { logger.Fatalf("Invalid key: %v", err) } - _, err = RunSocksSSClient(flags.BindAddr, flags.ListenPort, sc) + // TODO: add UDP support for ScoksToSS + _, err = RunSocksToSS(flags.BindAddr, flags.ListenPort, sc) if err != nil { logger.Fatalf("Failed running client: %v", err) } diff --git a/cmd/client/client_test.go b/cmd/client/socks2ss_test.go similarity index 83% rename from cmd/client/client_test.go rename to cmd/client/socks2ss_test.go index 1708afb5..02decfc5 100644 --- a/cmd/client/client_test.go +++ b/cmd/client/socks2ss_test.go @@ -36,32 +36,32 @@ const ( testSecret = "secret" ) -func TestParseKey(t *testing.T) { +func TestParseAccessKey(t *testing.T) { testCases := []struct { name string key string - want serverConfig + want sessionConfig wantErr bool }{ { name: "with b64 padding", - key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpteXBhc3N3b3JkCg==@127.0.0.1:9000/", - want: serverConfig{host: "127.0.0.1", port: 9000, cipher: "chacha20-ietf-poly1305", secret: "mypassword"}, + key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwYXNzd29yZA==@127.0.0.1:9000/", + want: sessionConfig{host: "127.0.0.1", port: 9000, cipher: "chacha20-ietf-poly1305", secret: "password"}, }, { name: "without b64 padding", - key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpteXBhc3N3b3JkCg@1.2.3.4:8080", - want: serverConfig{host: "1.2.3.4", port: 8080, cipher: "chacha20-ietf-poly1305", secret: "mypassword"}, + key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwYXNzd29yZA@1.2.3.4:8080", + want: sessionConfig{host: "1.2.3.4", port: 8080, cipher: "chacha20-ietf-poly1305", secret: "password"}, }, { name: "without b64", - key: "ss://chacha20-ietf-poly1305:mypassword@1.2.3.4:9000/", - want: serverConfig{host: "1.2.3.4", port: 9000, cipher: "chacha20-ietf-poly1305", secret: "mypassword"}, + key: "ss://chacha20-ietf-poly1305:password@1.2.3.4:9000/", + want: sessionConfig{host: "1.2.3.4", port: 9000, cipher: "chacha20-ietf-poly1305", secret: "password"}, }, { name: "with tag", - key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpteXBhc3N3b3JkCg@1.2.3.4:8080#TAG", - want: serverConfig{host: "1.2.3.4", port: 8080, cipher: "chacha20-ietf-poly1305", secret: "mypassword"}, + key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwYXNzd29yZA@1.2.3.4:8080#TAG", + want: sessionConfig{host: "1.2.3.4", port: 8080, cipher: "chacha20-ietf-poly1305", secret: "password"}, }, { name: "fail on no secret", @@ -70,14 +70,14 @@ func TestParseKey(t *testing.T) { }, { name: "fail on no port", - key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpteXBhc3N3b3JkCg@1.2.3.4#TAG", + key: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwYXNzd29yZA@1.2.3.4#TAG", wantErr: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - got, err := parseKey(tc.key) + got, err := parseAccessKey(tc.key) if err != nil { if !tc.wantErr { t.Errorf("parseKey('%s') got unexpected error: %v", tc.key, err) @@ -89,14 +89,14 @@ func TestParseKey(t *testing.T) { } } -func TestSSSocksClient(t *testing.T) { +func TestSocksToSS(t *testing.T) { ssSrvListener, ssSrv := startSSServer(t) defer ssSrv.Stop() echoListener, echoCloseCh := startEchoServer(t) defer echoListener.Close() - ssCli, err := RunSocksSSClient("127.0.0.1", 0, serverConfig{ + ssCli, err := RunSocksToSS("127.0.0.1", 0, sessionConfig{ host: "127.0.0.1", port: addrPort(t, ssSrvListener.Addr()), cipher: ss.TestCipher, @@ -128,7 +128,7 @@ func TestSSSocksClient(t *testing.T) { // Check that target connection closes after closing SOCKS connection select { case <-echoCloseCh: - t.Fatalf("SSServer<->EchoServer connection closed before SOCKS connection") + t.Fatalf("SSServer<->EchoServer connection closed before SOCKS connection closed") default: } socksCon.Close() @@ -179,12 +179,12 @@ func startEchoServer(t *testing.T) (net.Listener, chan struct{}) { go func() { c, err := l.Accept() if err != nil { - t.Fatalf("Accepting connection failed: %v\n", err) + t.Logf("Accepting connection failed: %v\n", err) return } _, err = io.Copy(c, c) if err != nil { - t.Fatalf(err.Error()) + t.Logf(err.Error()) } close(closeCh) }()