From 19bc41198efb6f01348a4e0c4744167b94b196dd Mon Sep 17 00:00:00 2001 From: a Date: Sun, 16 Jul 2023 01:31:06 -0500 Subject: [PATCH] [caplin] conn gater (#7900) conn gater so this is what prysm did to address the issue https://github.com/prysmaticlabs/prysm/pull/8648/files --- cmd/sentinel/cli/cliSettings.go | 2 + cmd/sentinel/cli/flags/flags.go | 5 ++ cmd/sentinel/main.go | 15 ++-- cmd/sentinel/sentinel/config.go | 15 ++-- cmd/sentinel/sentinel/gater.go | 139 ++++++++++++++++++++++++++++++ cmd/sentinel/sentinel/sentinel.go | 8 ++ p2p/discover/ntp.go | 3 +- 7 files changed, 172 insertions(+), 15 deletions(-) create mode 100644 cmd/sentinel/sentinel/gater.go diff --git a/cmd/sentinel/cli/cliSettings.go b/cmd/sentinel/cli/cliSettings.go index 10f05acfe..837eb1f16 100644 --- a/cmd/sentinel/cli/cliSettings.go +++ b/cmd/sentinel/cli/cliSettings.go @@ -33,6 +33,7 @@ type ConsensusClientCliCfg struct { ServerTcpPort uint `json:"serverTcpPort"` LogLvl uint `json:"logLevel"` NoDiscovery bool `json:"noDiscovery"` + LocalDiscovery bool `json:"localDiscovery"` CheckpointUri string `json:"checkpointUri"` Chaindata string `json:"chaindata"` ErigonPrivateApi string `json:"erigonPrivateApi"` @@ -117,6 +118,7 @@ func SetupConsensusClientCfg(ctx *cli.Context) (*ConsensusClientCliCfg, error) { cfg.LogLvl = uint(log.LvlDebug) } cfg.NoDiscovery = ctx.Bool(flags.NoDiscovery.Name) + cfg.LocalDiscovery = ctx.Bool(flags.LocalDiscovery.Name) if ctx.String(flags.CheckpointSyncUrlFlag.Name) != "" { cfg.CheckpointUri = ctx.String(flags.CheckpointSyncUrlFlag.Name) } else { diff --git a/cmd/sentinel/cli/flags/flags.go b/cmd/sentinel/cli/flags/flags.go index 9789cd225..cb2284a2d 100644 --- a/cmd/sentinel/cli/flags/flags.go +++ b/cmd/sentinel/cli/flags/flags.go @@ -80,6 +80,11 @@ var ( Usage: "turn off or on the lightclient finding peers", Value: false, } + LocalDiscovery = cli.BoolFlag{ + Name: "local-discovery", + Usage: "enable to also attempt to find peers over private ips. turning this on may cause issues with hosts such as hetzner", + Value: false, + } ChaindataFlag = cli.StringFlag{ Name: "chaindata", Usage: "chaindata of database", diff --git a/cmd/sentinel/main.go b/cmd/sentinel/main.go index 07040fca9..ec604b711 100644 --- a/cmd/sentinel/main.go +++ b/cmd/sentinel/main.go @@ -45,13 +45,14 @@ func runSentinelNode(cliCtx *cli.Context) error { log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(cfg.LogLvl), log.StderrHandler)) log.Info("[Sentinel] running sentinel with configuration", "cfg", cfg) _, err := service.StartSentinelService(&sentinel.SentinelConfig{ - IpAddr: cfg.Addr, - Port: int(cfg.Port), - TCPPort: cfg.ServerTcpPort, - GenesisConfig: cfg.GenesisCfg, - NetworkConfig: cfg.NetworkCfg, - BeaconConfig: cfg.BeaconCfg, - NoDiscovery: cfg.NoDiscovery, + IpAddr: cfg.Addr, + Port: int(cfg.Port), + TCPPort: cfg.ServerTcpPort, + GenesisConfig: cfg.GenesisCfg, + NetworkConfig: cfg.NetworkCfg, + BeaconConfig: cfg.BeaconCfg, + NoDiscovery: cfg.NoDiscovery, + LocalDiscovery: cfg.LocalDiscovery, }, nil, &service.ServerConfig{Network: cfg.ServerProtocol, Addr: cfg.ServerAddr}, nil, nil, log.Root()) if err != nil { log.Error("[Sentinel] Could not start sentinel", "err", err) diff --git a/cmd/sentinel/sentinel/config.go b/cmd/sentinel/sentinel/config.go index dece3552b..96af15c85 100644 --- a/cmd/sentinel/sentinel/config.go +++ b/cmd/sentinel/sentinel/config.go @@ -36,13 +36,14 @@ type SentinelConfig struct { Port int TCPPort uint // Optional - LocalIP string - EnableUPnP bool - RelayNodeAddr string - HostAddress string - HostDNS string - NoDiscovery bool - TmpDir string + LocalIP string + EnableUPnP bool + RelayNodeAddr string + HostAddress string + HostDNS string + NoDiscovery bool + TmpDir string + LocalDiscovery bool } func convertToCryptoPrivkey(privkey *ecdsa.PrivateKey) (crypto.PrivKey, error) { diff --git a/cmd/sentinel/sentinel/gater.go b/cmd/sentinel/sentinel/gater.go new file mode 100644 index 000000000..1c4ec20f2 --- /dev/null +++ b/cmd/sentinel/sentinel/gater.go @@ -0,0 +1,139 @@ +package sentinel + +import ( + "net" + + "github.com/libp2p/go-libp2p/core/control" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" +) + +var privateCIDRList = []string{ + // https://tools.ietf.org/html/rfc1918 + "10.0.0.0/8", + "172.16.0.0/12", + "192.168.0.0/16", + // https://tools.ietf.org/html/rfc6598 + "100.64.0.0/10", + // https://tools.ietf.org/html/rfc3927 + "169.254.0.0/16", +} + +type Gater struct { + filter *multiaddr.Filters +} + +func NewGater(cfg *SentinelConfig) (g *Gater, err error) { + g = &Gater{} + g.filter, err = configureFilter(cfg) + if err != nil { + return nil, err + } + return g, nil +} + +// InterceptPeerDial tests whether we're permitted to Dial the specified peer. +// This is called by the network.Network implementation when dialling a peer. +func (g *Gater) InterceptPeerDial(p peer.ID) (allow bool) { + return true +} + +// InterceptAddrDial tests whether we're permitted to dial the specified +// multiaddr for the given peer. +// +// This is called by the network.Network implementation after it has +// resolved the peer's addrs, and prior to dialling each. +func (g *Gater) InterceptAddrDial(_ peer.ID, n multiaddr.Multiaddr) (allow bool) { + return filterConnections(g.filter, n) +} + +// InterceptAccept tests whether an incipient inbound connection is allowed. +// +// This is called by the upgrader, or by the transport directly (e.g. QUIC, +// Bluetooth), straight after it has accepted a connection from its socket. +func (g *Gater) InterceptAccept(n network.ConnMultiaddrs) (allow bool) { + return filterConnections(g.filter, n.RemoteMultiaddr()) +} + +// InterceptSecured tests whether a given connection, now authenticated, +// is allowed. +// +// This is called by the upgrader, after it has performed the security +// handshake, and before it negotiates the muxer, or by the directly by the +// transport, at the exact same checkpoint. +func (g *Gater) InterceptSecured(_ network.Direction, _ peer.ID, _ network.ConnMultiaddrs) (allow bool) { + return true +} + +// InterceptUpgraded tests whether a fully capable connection is allowed. +// +// At this point, the connection a multiplexer has been selected. +// When rejecting a connection, the gater can return a DisconnectReason. +// Refer to the godoc on the ConnectionGater type for more information. +// +// NOTE: the go-libp2p implementation currently IGNORES the disconnect reason. +func (g *Gater) InterceptUpgraded(_ network.Conn) (allow bool, reason control.DisconnectReason) { + return true, 0 +} + +func filterConnections(f *multiaddr.Filters, a multiaddr.Multiaddr) bool { + acceptedNets := f.FiltersForAction(multiaddr.ActionAccept) + restrictConns := len(acceptedNets) != 0 + + // If we have an allow list added in, we by default reject all + // connection attempts except for those coming in from the + // appropriate ip subnets. + if restrictConns { + ip, err := manet.ToIP(a) + if err != nil { + return false + } + found := false + for _, ipnet := range acceptedNets { + if ipnet.Contains(ip) { + found = true + break + } + } + return found + } + return !f.AddrBlocked(a) +} + +func configureFilter(cfg *SentinelConfig) (*multiaddr.Filters, error) { + var err error + addrFilter := multiaddr.NewFilters() + if !cfg.LocalDiscovery { + addrFilter, err = privateCIDRFilter(addrFilter, multiaddr.ActionDeny) + if err != nil { + return nil, err + } + } + return addrFilter, nil +} + +// helper function to either accept or deny all private addresses +// if a new rule for a private address is in conflict with a previous one, log a warning +func privateCIDRFilter(addrFilter *multiaddr.Filters, action multiaddr.Action) (*multiaddr.Filters, error) { + for _, privCidr := range privateCIDRList { + _, ipnet, err := net.ParseCIDR(privCidr) + if err != nil { + return nil, err + } + // curAction, _ := addrFilter.ActionForFilter(*ipnet) + // switch { + // case action == multiaddr.ActionAccept: + // if curAction == multiaddr.ActionDeny { + // // rule conflict + // } + // case action == multiaddr.ActionDeny: + // if curAction == multiaddr.ActionAccept { + // // rule conflict + // } + // } + addrFilter.AddFilter(*ipnet, action) + } + return addrFilter, nil +} diff --git a/cmd/sentinel/sentinel/sentinel.go b/cmd/sentinel/sentinel/sentinel.go index 73983d432..7e9e9bf11 100644 --- a/cmd/sentinel/sentinel/sentinel.go +++ b/cmd/sentinel/sentinel/sentinel.go @@ -276,6 +276,14 @@ func New( } opts = append(opts, libp2p.ResourceManager(rmgr)) } + + gater, err := NewGater(cfg) + if err != nil { + return nil, err + } + + opts = append(opts, libp2p.ConnectionGater(gater)) + host, err := libp2p.New(opts...) if err != nil { return nil, err diff --git a/p2p/discover/ntp.go b/p2p/discover/ntp.go index dbcd1108c..e321608c9 100644 --- a/p2p/discover/ntp.go +++ b/p2p/discover/ntp.go @@ -105,7 +105,8 @@ func sntpDrift(measurements int) (time.Duration, error) { nanosec := sec*1e9 + (frac*1e9)>>32 - t := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(nanosec)).Local() + // nolint:gosmopolitan + t := time.Date(1900, 1, 1, 0, 0, 0, 0, time.Local).Add(time.Duration(nanosec)) // Calculate the drift based on an assumed answer time of RRT/2 drifts = append(drifts, sent.Sub(t)+elapsed/2)