diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 850e26d161..1ffc146618 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -125,6 +125,7 @@ var ( utils.NoDiscoverFlag, utils.DiscoveryV4Flag, utils.DiscoveryV5Flag, + utils.UseProxyFlag, utils.LegacyDiscoveryV5Flag, // deprecated utils.NetrestrictFlag, utils.NodeKeyFileFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ea0f6f5ee4..61f635549a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -911,6 +911,11 @@ var ( Category: flags.NetworkingCategory, Value: node.DefaultConfig.P2P.DiscoveryV5, } + UseProxyFlag = &cli.BoolFlag{ + Name: "use-proxy", + Usage: "Use SOCKS5 proxy from ALL_PROXY or all_proxy environment variable for peer connections", + Category: flags.NetworkingCategory, + } NetrestrictFlag = &cli.StringFlag{ Name: "netrestrict", Usage: "Restricts network communication to the given IP networks (CIDR masks)", @@ -1473,6 +1478,7 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { if ctx.IsSet(DiscoveryV5Flag.Name) { cfg.DiscoveryV5 = ctx.Bool(DiscoveryV5Flag.Name) } + cfg.UseProxy = ctx.Bool(UseProxyFlag.Name) if netrestrict := ctx.String(NetrestrictFlag.Name); netrestrict != "" { list, err := netutil.ParseNetlist(netrestrict) diff --git a/p2p/config.go b/p2p/config.go index 17607a1f88..439eac8c1d 100644 --- a/p2p/config.go +++ b/p2p/config.go @@ -124,6 +124,9 @@ type Config struct { // Logger is a custom logger to use with the p2p.Server. Logger log.Logger `toml:"-"` + // If UseProxy is set to true, the server will use SOCKS5 proxy from ALL_PROXY or all_proxy environment variable for dialing peers. + UseProxy bool `toml:",omitempty"` + clock mclock.Clock } diff --git a/p2p/config_toml.go b/p2p/config_toml.go index 8a255e62fb..5157e51bd3 100644 --- a/p2p/config_toml.go +++ b/p2p/config_toml.go @@ -38,6 +38,7 @@ func (c Config) MarshalTOML() (interface{}, error) { NoDial bool `toml:",omitempty"` EnableMsgEvents bool Logger log.Logger `toml:"-"` + UseProxy bool `toml:",omitempty"` } var enc Config enc.PrivateKey = c.PrivateKey @@ -62,6 +63,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.NoDial = c.NoDial enc.EnableMsgEvents = c.EnableMsgEvents enc.Logger = c.Logger + enc.UseProxy = c.UseProxy return &enc, nil } @@ -90,6 +92,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { NoDial *bool `toml:",omitempty"` EnableMsgEvents *bool Logger log.Logger `toml:"-"` + UseProxy *bool `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { @@ -161,5 +164,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.Logger != nil { c.Logger = dec.Logger } + if dec.UseProxy != nil { + c.UseProxy = *dec.UseProxy + } return nil } diff --git a/p2p/dial.go b/p2p/dial.go index f9463d6d89..818d8b0774 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/netutil" + "golang.org/x/net/proxy" ) const ( @@ -63,11 +64,28 @@ type nodeResolver interface { // tcpDialer implements NodeDialer using real TCP connections. type tcpDialer struct { - d *net.Dialer + d *net.Dialer + useProxy bool } +// dialerWithContext is an interface implemented by proxy dialers that support context-aware dialing. +// see proxy/direct#direct, proxy.SOCKS5() and internal/socks#Dialer. +type dialerWithContext interface { + DialContext(ctx context.Context, network, address string) (net.Conn, error) +} + +var proxyDialer = proxy.FromEnvironment() + func (t tcpDialer) Dial(ctx context.Context, dest *enode.Node) (net.Conn, error) { addr, _ := dest.TCPEndpoint() + if t.useProxy { + log.Debug("Dialing peer via proxy", "direct", proxyDialer == proxy.Direct, "addr", addr.String()) + if v, ok := proxyDialer.(dialerWithContext); ok { + return v.DialContext(ctx, "tcp", addr.String()) + } else { + log.Warn("Proxy dialer does not support context, falling back to direct", "addr", addr.String()) + } + } return t.d.DialContext(ctx, "tcp", addr.String()) } diff --git a/p2p/server.go b/p2p/server.go index 6d2323f9ce..eb08708c51 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -537,7 +537,7 @@ func (srv *Server) setupDialScheduler() { config.resolver = srv.discv4 } if config.dialer == nil { - config.dialer = tcpDialer{&net.Dialer{Timeout: defaultDialTimeout}} + config.dialer = tcpDialer{&net.Dialer{Timeout: defaultDialTimeout}, srv.UseProxy} } srv.dialsched = newDialScheduler(config, srv.discmix, srv.SetupConn) for _, n := range srv.StaticNodes {