From a0cb88e2cf78da4a78bcfb09e641e72cf137c05f Mon Sep 17 00:00:00 2001 From: cloorc Date: Tue, 2 Dec 2025 16:08:48 +0800 Subject: [PATCH] p2p: add optional SOCKS5 proxy support for outbound peer dials - Add `UseProxy` field to `p2p.Config` and corresponding `--use-proxy` CLI flag. - Implement proxy-aware `tcpDialer` (uses `golang.org/x/net/proxy` and attempts context-aware DialContext when supported). - Wire `UseProxy` through `Server` to the dialer so peer dials can go via SOCKS5 proxy defined by `ALL_PROXY`/`all_proxy`. - Minor debug `start.sh` for running geth with `--use-proxy`. Signed-off-by: cloorc --- cmd/geth/main.go | 1 + cmd/utils/flags.go | 6 ++++++ go.mod | 2 +- p2p/config.go | 3 +++ p2p/config_toml.go | 6 ++++++ p2p/dial.go | 20 +++++++++++++++++++- p2p/server.go | 2 +- 7 files changed, 37 insertions(+), 3 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 851ae1ce0bb..1b71c999b9c 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -126,6 +126,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 996cb276ee4..137aff86cc4 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -873,6 +873,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)", @@ -1379,6 +1384,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/go.mod b/go.mod index aff1d53923c..219f0edf581 100644 --- a/go.mod +++ b/go.mod @@ -144,7 +144,7 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.38.0 // indirect + golang.org/x/net v0.38.0 gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/p2p/config.go b/p2p/config.go index 17607a1f882..439eac8c1d7 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 8a255e62fbb..5157e51bd32 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 225709427c2..77e77eb46f4 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 10c855f1c46..2eabb8fae5c 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 {