diff --git a/outline/android/tun2socks.go b/outline/android/tun2socks.go index c0dd47c..c36d74b 100644 --- a/outline/android/tun2socks.go +++ b/outline/android/tun2socks.go @@ -21,6 +21,7 @@ import ( "github.com/Jigsaw-Code/outline-go-tun2socks/outline" "github.com/Jigsaw-Code/outline-go-tun2socks/tunnel" + "github.com/Jigsaw-Code/outline-ss-server/client" "github.com/eycorsican/go-tun2socks/common/log" ) @@ -58,7 +59,11 @@ func ConnectShadowsocksTunnel(fd int, host string, port int, password, cipher st if err != nil { return nil, err } - t, err := outline.NewTunnel(host, port, password, cipher, isUDPEnabled, tun) + ssclient, err := client.NewClient(host, port, password, cipher) + if err != nil { + return nil, fmt.Errorf("failed to construct Shadowsocks client: %v", err) + } + t, err := outline.NewTunnel(ssclient, isUDPEnabled, tun) if err != nil { return nil, err } diff --git a/outline/apple/tun2socks.go b/outline/apple/tun2socks.go index dbcdb1d..7cc9078 100644 --- a/outline/apple/tun2socks.go +++ b/outline/apple/tun2socks.go @@ -23,6 +23,7 @@ import ( "time" "github.com/Jigsaw-Code/outline-go-tun2socks/outline" + "github.com/Jigsaw-Code/outline-ss-server/client" ) // OutlineTunnel embeds the tun2socks.Tunnel interface so it gets exported by gobind. @@ -66,5 +67,10 @@ func ConnectShadowsocksTunnel(tunWriter TunWriter, host string, port int, passwo } else if port <= 0 || port > math.MaxUint16 { return nil, fmt.Errorf("Invalid port number: %v", port) } - return outline.NewTunnel(host, port, password, cipher, isUDPEnabled, tunWriter) + ssclient, err := client.NewClient(host, port, password, cipher) + if err != nil { + return nil, fmt.Errorf("failed to construct Shadowsocks client: %v", err) + } + + return outline.NewTunnel(ssclient, isUDPEnabled, tunWriter) } diff --git a/outline/electron/main.go b/outline/electron/main.go index e3b1f71..273b838 100644 --- a/outline/electron/main.go +++ b/outline/electron/main.go @@ -26,6 +26,7 @@ import ( oss "github.com/Jigsaw-Code/outline-go-tun2socks/outline/shadowsocks" "github.com/Jigsaw-Code/outline-go-tun2socks/shadowsocks" + "github.com/Jigsaw-Code/outline-ss-server/client" "github.com/eycorsican/go-tun2socks/common/log" _ "github.com/eycorsican/go-tun2socks/common/log/simple" // Register a simple logger. "github.com/eycorsican/go-tun2socks/core" @@ -115,16 +116,20 @@ func main() { // Output packets to TUN device core.RegisterOutputFn(tunDevice.Write) + ssclient, err := client.NewClient(*args.proxyHost, *args.proxyPort, *args.proxyPassword, *args.proxyCipher) + if err != nil { + log.Errorf("Failed to construct Shadowsocks client: %v", err) + os.Exit(oss.IllegalConfiguration) + } + // Register TCP and UDP connection handlers - core.RegisterTCPConnHandler( - shadowsocks.NewTCPHandler(*args.proxyHost, *args.proxyPort, *args.proxyPassword, *args.proxyCipher)) + core.RegisterTCPConnHandler(shadowsocks.NewTCPHandler(ssclient)) if *args.dnsFallback { // UDP connectivity not supported, fall back to DNS over TCP. log.Debugf("Registering DNS fallback UDP handler") core.RegisterUDPConnHandler(dnsfallback.NewUDPHandler()) } else { - core.RegisterUDPConnHandler( - shadowsocks.NewUDPHandler(*args.proxyHost, *args.proxyPort, *args.proxyPassword, *args.proxyCipher, udpTimeout)) + core.RegisterUDPConnHandler(shadowsocks.NewUDPHandler(ssclient, udpTimeout)) } // Configure LWIP stack to receive input data from the TUN device diff --git a/outline/tunnel.go b/outline/tunnel.go index b27d41f..49cd142 100644 --- a/outline/tunnel.go +++ b/outline/tunnel.go @@ -16,7 +16,6 @@ package outline import ( "errors" - "fmt" "io" "time" @@ -41,10 +40,7 @@ type Tunnel interface { type outlinetunnel struct { tunnel.Tunnel lwipStack core.LWIPStack - host string - port int - password string - cipher string + client shadowsocks.Client isUDPEnabled bool // Whether the tunnel supports proxying UDP. } @@ -56,30 +52,22 @@ type outlinetunnel struct { // `cipher` is the encryption cipher used by the Shadowsocks proxy. // `isUDPEnabled` indicates if the Shadowsocks proxy and the network support proxying UDP traffic. // `tunWriter` is used to output packets back to the TUN device. OutlineTunnel.Disconnect() will close `tunWriter`. -func NewTunnel(host string, port int, password, cipher string, isUDPEnabled bool, tunWriter io.WriteCloser) (Tunnel, error) { +func NewTunnel(client shadowsocks.Client, isUDPEnabled bool, tunWriter io.WriteCloser) (Tunnel, error) { if tunWriter == nil { return nil, errors.New("Must provide a TUN writer") } - _, err := shadowsocks.NewClient(host, port, password, cipher) - if err != nil { - return nil, fmt.Errorf("Invalid Shadowsocks proxy parameters: %v", err.Error()) - } core.RegisterOutputFn(func(data []byte) (int, error) { return tunWriter.Write(data) }) lwipStack := core.NewLWIPStack() base := tunnel.NewTunnel(tunWriter, lwipStack) - t := &outlinetunnel{base, lwipStack, host, port, password, cipher, isUDPEnabled} + t := &outlinetunnel{base, lwipStack, client, isUDPEnabled} t.registerConnectionHandlers() return t, nil } func (t *outlinetunnel) UpdateUDPSupport() bool { - client, err := shadowsocks.NewClient(t.host, t.port, t.password, t.cipher) - if err != nil { - return false - } - isUDPEnabled := oss.CheckUDPConnectivityWithDNS(client, shadowsocks.NewAddr("1.1.1.1:53", "udp")) == nil + isUDPEnabled := oss.CheckUDPConnectivityWithDNS(t.client, shadowsocks.NewAddr("1.1.1.1:53", "udp")) == nil if t.isUDPEnabled != isUDPEnabled { t.isUDPEnabled = isUDPEnabled t.lwipStack.Close() // Close existing connections to avoid using the previous handlers. @@ -93,10 +81,10 @@ func (t *outlinetunnel) UpdateUDPSupport() bool { func (t *outlinetunnel) registerConnectionHandlers() { var udpHandler core.UDPConnHandler if t.isUDPEnabled { - udpHandler = oss.NewUDPHandler(t.host, t.port, t.password, t.cipher, 30*time.Second) + udpHandler = oss.NewUDPHandler(t.client, 30*time.Second) } else { udpHandler = dnsfallback.NewUDPHandler() } - core.RegisterTCPConnHandler(oss.NewTCPHandler(t.host, t.port, t.password, t.cipher)) + core.RegisterTCPConnHandler(oss.NewTCPHandler(t.client)) core.RegisterUDPConnHandler(udpHandler) } diff --git a/shadowsocks/tcp.go b/shadowsocks/tcp.go index 6f2b201..361ccdb 100644 --- a/shadowsocks/tcp.go +++ b/shadowsocks/tcp.go @@ -3,8 +3,8 @@ package shadowsocks import ( "net" - onet "github.com/Jigsaw-Code/outline-ss-server/net" shadowsocks "github.com/Jigsaw-Code/outline-ss-server/client" + onet "github.com/Jigsaw-Code/outline-ss-server/net" "github.com/eycorsican/go-tun2socks/core" ) @@ -13,16 +13,7 @@ type tcpHandler struct { } // NewTCPHandler returns a Shadowsocks TCP connection handler. -// -// `host` is the hostname of the Shadowsocks proxy server. -// `port` is the port of the Shadowsocks proxy server. -// `password` is password used to authenticate to the server. -// `cipher` is the encryption cipher of the Shadowsocks proxy. -func NewTCPHandler(host string, port int, password, cipher string) core.TCPConnHandler { - client, err := shadowsocks.NewClient(host, port, password, cipher) - if err != nil { - return nil - } +func NewTCPHandler(client shadowsocks.Client) core.TCPConnHandler { return &tcpHandler{client} } diff --git a/shadowsocks/udp.go b/shadowsocks/udp.go index 3e0070a..adeeffc 100644 --- a/shadowsocks/udp.go +++ b/shadowsocks/udp.go @@ -20,16 +20,9 @@ type udpHandler struct { // NewUDPHandler returns a Shadowsocks UDP connection handler. // -// `host` is the hostname of the Shadowsocks proxy server. -// `port` is the port of the Shadowsocks proxy. -// `password` is password used to authenticate to the proxy. -// `cipher` is the encryption cipher of the Shadowsocks proxy. +// `client` provides the Shadowsocks functionality. // `timeout` is the UDP read and write timeout. -func NewUDPHandler(host string, port int, password, cipher string, timeout time.Duration) core.UDPConnHandler { - client, err := shadowsocks.NewClient(host, port, password, cipher) - if err != nil { - return nil - } +func NewUDPHandler(client shadowsocks.Client, timeout time.Duration) core.UDPConnHandler { return &udpHandler{ client: client, timeout: timeout,