Browse Source

Add proxy support (fixes #271)

Audrius Butkevicius 10 years ago
parent
commit
985ea29940

+ 2 - 1
cmd/syncthing/usage_report.go

@@ -20,6 +20,7 @@ import (
 	"time"
 
 	"github.com/syncthing/syncthing/lib/config"
+	"github.com/syncthing/syncthing/lib/dialer"
 	"github.com/syncthing/syncthing/lib/model"
 	"github.com/syncthing/syncthing/lib/protocol"
 	"github.com/syncthing/syncthing/lib/upgrade"
@@ -261,7 +262,7 @@ func (s *usageReportingService) sendUsageReport() error {
 	if BuildEnv == "android" {
 		// This works around the lack of DNS resolution on Android... :(
 		transp.Dial = func(network, addr string) (net.Conn, error) {
-			return net.Dial(network, "194.126.249.13:443")
+			return dialer.Dial(network, "194.126.249.13:443")
 		}
 	}
 

+ 3 - 2
lib/connections/connections_tcp.go

@@ -12,6 +12,7 @@ import (
 	"net/url"
 	"strings"
 
+	"github.com/syncthing/syncthing/lib/dialer"
 	"github.com/syncthing/syncthing/lib/model"
 	"github.com/syncthing/syncthing/lib/osutil"
 )
@@ -37,13 +38,13 @@ func tcpDialer(uri *url.URL, tlsCfg *tls.Config) (*tls.Conn, error) {
 		return nil, err
 	}
 
-	conn, err := net.DialTCP("tcp", nil, raddr)
+	conn, err := dialer.Dial(raddr.Network(), raddr.String())
 	if err != nil {
 		l.Debugln(err)
 		return nil, err
 	}
 
-	err = osutil.SetTCPOptions(conn)
+	err = osutil.SetTCPOptions(conn.(*net.TCPConn))
 	if err != nil {
 		l.Infoln(err)
 	}

+ 88 - 0
lib/dialer/dialer.go

@@ -0,0 +1,88 @@
+// Copyright (C) 2015 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package dialer
+
+import (
+	"net"
+	"os"
+	"strings"
+	"time"
+
+	"golang.org/x/net/proxy"
+
+	"github.com/syncthing/syncthing/lib/logger"
+)
+
+var (
+	l          = logger.DefaultLogger.NewFacility("dialer", "Dialing connections")
+	dialer     = proxy.FromEnvironment()
+	usingProxy = dialer != proxy.Direct
+)
+
+func init() {
+	l.SetDebug("dialer", strings.Contains(os.Getenv("STTRACE"), "dialer") || os.Getenv("STTRACE") == "all")
+	if usingProxy {
+		// Defer this, so that logging gets setup.
+		go func() {
+			time.Sleep(500 * time.Millisecond)
+			l.Infoln("Proxy settings detected")
+		}()
+	}
+}
+
+// Dial tries dialing via proxy if a proxy is configured, and falls back to
+// a direct connection if no proxy is defined, or connecting via proxy fails.
+func Dial(network, addr string) (net.Conn, error) {
+	if usingProxy {
+		conn, err := dialer.Dial(network, addr)
+		if err == nil {
+			l.Debugf("Dialing %s address %s via proxy - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr())
+			return dialerConn{
+				conn, newDialerAddr(network, addr),
+			}, nil
+		}
+		l.Debugf("Dialing %s address %s via proxy - error %s", network, addr, err)
+	}
+
+	conn, err := proxy.Direct.Dial(network, addr)
+	if err == nil {
+		l.Debugf("Dialing %s address %s directly - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr())
+	} else {
+		l.Debugf("Dialing %s address %s directly - error %s", network, addr, err)
+	}
+	return conn, err
+}
+
+type dialerConn struct {
+	net.Conn
+	addr net.Addr
+}
+
+func (c dialerConn) RemoteAddr() net.Addr {
+	return c.addr
+}
+
+func newDialerAddr(network, addr string) net.Addr {
+	netaddr, err := net.ResolveIPAddr(network, addr)
+	if err == nil {
+		return netaddr
+	}
+	return fallbackAddr{network, addr}
+}
+
+type fallbackAddr struct {
+	network string
+	addr    string
+}
+
+func (a fallbackAddr) Network() string {
+	return a.network
+}
+
+func (a fallbackAddr) String() string {
+	return a.addr
+}

+ 2 - 1
lib/relay/client/client.go

@@ -9,6 +9,7 @@ import (
 	"net/url"
 	"time"
 
+	"github.com/syncthing/syncthing/lib/dialer"
 	syncthingprotocol "github.com/syncthing/syncthing/lib/protocol"
 	"github.com/syncthing/syncthing/lib/relay/protocol"
 	"github.com/syncthing/syncthing/lib/sync"
@@ -172,7 +173,7 @@ func (c *ProtocolClient) connect() error {
 	}
 
 	t0 := time.Now()
-	tcpConn, err := net.Dial("tcp", c.URI.Host)
+	tcpConn, err := dialer.Dial("tcp", c.URI.Host)
 	if err != nil {
 		return err
 	}

+ 5 - 2
lib/relay/client/methods.go

@@ -11,6 +11,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/syncthing/syncthing/lib/dialer"
 	syncthingprotocol "github.com/syncthing/syncthing/lib/protocol"
 	"github.com/syncthing/syncthing/lib/relay/protocol"
 )
@@ -20,10 +21,12 @@ func GetInvitationFromRelay(uri *url.URL, id syncthingprotocol.DeviceID, certs [
 		return protocol.SessionInvitation{}, fmt.Errorf("Unsupported relay scheme: %v", uri.Scheme)
 	}
 
-	conn, err := tls.Dial("tcp", uri.Host, configForCerts(certs))
+	rconn, err := dialer.Dial("tcp", uri.Host)
 	if err != nil {
 		return protocol.SessionInvitation{}, err
 	}
+
+	conn := tls.Client(rconn, configForCerts(certs))
 	conn.SetDeadline(time.Now().Add(10 * time.Second))
 
 	if err := performHandshakeAndValidation(conn, uri); err != nil {
@@ -63,7 +66,7 @@ func GetInvitationFromRelay(uri *url.URL, id syncthingprotocol.DeviceID, certs [
 func JoinSession(invitation protocol.SessionInvitation) (net.Conn, error) {
 	addr := net.JoinHostPort(net.IP(invitation.Address).String(), strconv.Itoa(int(invitation.Port)))
 
-	conn, err := net.Dial("tcp", addr)
+	conn, err := dialer.Dial("tcp", addr)
 	if err != nil {
 		return nil, err
 	}

+ 2 - 1
lib/upnp/upnp.go

@@ -25,6 +25,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/syncthing/syncthing/lib/dialer"
 	"github.com/syncthing/syncthing/lib/sync"
 )
 
@@ -289,7 +290,7 @@ func parseResponse(deviceType string, resp []byte) (IGD, error) {
 }
 
 func localIP(url *url.URL) (string, error) {
-	conn, err := net.Dial("tcp", url.Host)
+	conn, err := dialer.Dial("tcp", url.Host)
 	if err != nil {
 		return "", err
 	}