From 0651a401e09a70e367a558a48ec752968127a067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Thu, 14 Jul 2022 18:24:27 +0700 Subject: [PATCH 01/18] cmd, p2p: implement sentry node --- cmd/geth/main.go | 2 ++ cmd/geth/usage.go | 2 ++ cmd/utils/flags.go | 16 ++++++++++++++++ p2p/dial.go | 5 +++++ p2p/discover/common.go | 25 +++++++++++++++++++------ p2p/discover/v4_udp.go | 29 ++++++++++++++++++++--------- p2p/discover/v5_udp.go | 31 ++++++++++++++++++++++--------- p2p/netutil/net.go | 15 +++++++++++++++ p2p/server.go | 17 +++++++++++++++++ p2p/util.go | 11 +++++++++++ 10 files changed, 129 insertions(+), 24 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index da62b8d4d4d2..78e953a34755 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -129,6 +129,8 @@ var ( utils.NoDiscoverFlag, utils.DiscoveryV5Flag, utils.NetrestrictFlag, + utils.SentryNodeFlag, + utils.ValidatorNodeFlag, utils.NodeKeyFileFlag, utils.NodeKeyHexFlag, utils.DNSDiscoveryFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 708edcc79325..f022aa6e7f75 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -169,6 +169,8 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.NoDiscoverFlag, utils.DiscoveryV5Flag, utils.NetrestrictFlag, + utils.SentryNodeFlag, + utils.ValidatorNodeFlag, utils.NodeKeyFileFlag, utils.NodeKeyHexFlag, }, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 61c33ad8a262..3a064f874a7d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -656,6 +656,14 @@ var ( Name: "netrestrict", Usage: "Restricts network communication to the given IP networks (CIDR masks)", } + SentryNodeFlag = cli.StringFlag{ + Name: "sentrynodes", + Usage: "Restricts network communication to the given IP addresses", + } + ValidatorNodeFlag = cli.StringFlag{ + Name: "validatornodes", + Usage: "Validator node list for sentry node", + } DNSDiscoveryFlag = cli.StringFlag{ Name: "discovery.dns", Usage: "Sets DNS discovery entry points (use \"\" to disable DNS)", @@ -1197,6 +1205,14 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { cfg.NetRestrict = list } + if sentrynodes := ctx.GlobalString(SentryNodeFlag.Name); sentrynodes != "" { + cfg.SentryNodes = netutil.ParseIPs(sentrynodes) + } + + if validatornodes := ctx.GlobalString(ValidatorNodeFlag.Name); validatornodes != "" { + cfg.ValidatorNodes = netutil.ParseIPs(validatornodes) + } + if ctx.GlobalBool(DeveloperFlag.Name) || ctx.GlobalBool(CatalystFlag.Name) { // --dev mode can't use p2p networking. cfg.MaxPeers = 0 diff --git a/p2p/dial.go b/p2p/dial.go index 5cca5ad8c692..463cb9596267 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -79,6 +79,7 @@ var ( errAlreadyListened = errors.New("already listened") errRecentlyDialed = errors.New("recently dialed") errNetRestrict = errors.New("not contained in netrestrict list") + errSentryNode = errors.New("not contained in sentry nodes") errNoPort = errors.New("node does not provide TCP port") ) @@ -135,6 +136,7 @@ type dialConfig struct { maxDialPeers int // maximum number of dialed peers maxActiveDials int // maximum number of active dials netRestrict *netutil.Netlist // IP netrestrict list, disabled if nil + sentryNodes []string // IP address restrict list, disabled if nil resolver nodeResolver dialer NodeDialer log log.Logger @@ -405,6 +407,9 @@ func (d *dialScheduler) checkDial(n *enode.Node) error { if d.netRestrict != nil && !d.netRestrict.Contains(n.IP()) { return errNetRestrict } + if len(d.sentryNodes) > 0 && !contains(d.sentryNodes, n.IP().String()) { + return errSentryNode + } if d.history.contains(string(n.ID().Bytes())) { return errRecentlyDialed } diff --git a/p2p/discover/common.go b/p2p/discover/common.go index e389821fda8b..2caba04c5ec3 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -41,12 +41,14 @@ type Config struct { PrivateKey *ecdsa.PrivateKey // These settings are optional: - NetRestrict *netutil.Netlist // list of allowed IP networks - Bootnodes []*enode.Node // list of bootstrap nodes - Unhandled chan<- ReadPacket // unhandled packets are sent on this channel - Log log.Logger // if set, log messages go here - ValidSchemes enr.IdentityScheme // allowed identity schemes - Clock mclock.Clock + NetRestrict *netutil.Netlist // list of allowed IP networks + SentryNodes []string // list of allowed IPs + ValidatorNodes []string // list of validator IPs + Bootnodes []*enode.Node // list of bootstrap nodes + Unhandled chan<- ReadPacket // unhandled packets are sent on this channel + Log log.Logger // if set, log messages go here + ValidSchemes enr.IdentityScheme // allowed identity schemes + Clock mclock.Clock } func (cfg Config) withDefaults() Config { @@ -80,3 +82,14 @@ func min(x, y int) int { } return x } + +// contains checks if a string is present in a slice +func has(s []string, str string) bool { + for _, v := range s { + if v == str { + return true + } + } + + return false +} diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 334716aebed0..a953cb2406ae 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -65,15 +65,17 @@ const ( // UDPv4 implements the v4 wire protocol. type UDPv4 struct { - conn UDPConn - log log.Logger - netrestrict *netutil.Netlist - priv *ecdsa.PrivateKey - localNode *enode.LocalNode - db *enode.DB - tab *Table - closeOnce sync.Once - wg sync.WaitGroup + conn UDPConn + log log.Logger + netrestrict *netutil.Netlist + sentryNodes []string + validatorNodes []string + priv *ecdsa.PrivateKey + localNode *enode.LocalNode + db *enode.DB + tab *Table + closeOnce sync.Once + wg sync.WaitGroup addReplyMatcher chan *replyMatcher gotreply chan reply @@ -133,6 +135,8 @@ func ListenV4(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) { conn: c, priv: cfg.PrivateKey, netrestrict: cfg.NetRestrict, + sentryNodes: cfg.SentryNodes, + validatorNodes: cfg.ValidatorNodes, localNode: ln, db: ln.Database(), gotreply: make(chan reply), @@ -585,6 +589,9 @@ func (t *UDPv4) nodeFromRPC(sender *net.UDPAddr, rn v4wire.Node) (*node, error) if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) { return nil, errors.New("not contained in netrestrict list") } + if len(t.sentryNodes) > 0 && !has(t.sentryNodes, rn.IP.String()) { + return nil, errors.New("not contained in sentry nodes") + } key, err := v4wire.DecodePubkey(crypto.S256(), rn.ID) if err != nil { return nil, err @@ -728,6 +735,10 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno p := v4wire.Neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} var sent bool for _, n := range closest { + // Get rid of validator node out of the found node + if len(t.validatorNodes) > 0 && has(t.validatorNodes, n.IP().String()) { + continue + } if netutil.CheckRelayIP(from.IP, n.IP()) == nil { p.Nodes = append(p.Nodes, nodeToRPC(n)) } diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 71a39ea5a5f9..4bb6b53ff1a9 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -62,15 +62,17 @@ type codecV5 interface { // UDPv5 is the implementation of protocol version 5. type UDPv5 struct { // static fields - conn UDPConn - tab *Table - netrestrict *netutil.Netlist - priv *ecdsa.PrivateKey - localNode *enode.LocalNode - db *enode.DB - log log.Logger - clock mclock.Clock - validSchemes enr.IdentityScheme + conn UDPConn + tab *Table + netrestrict *netutil.Netlist + sentryNodes []string + validatorNodes []string + priv *ecdsa.PrivateKey + localNode *enode.LocalNode + db *enode.DB + log log.Logger + clock mclock.Clock + validSchemes enr.IdentityScheme // talkreq handler registry trlock sync.Mutex @@ -144,6 +146,7 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { localNode: ln, db: ln.Database(), netrestrict: cfg.NetRestrict, + sentryNodes: cfg.SentryNodes, priv: cfg.PrivateKey, log: cfg.Log, validSchemes: cfg.ValidSchemes, @@ -309,6 +312,12 @@ func (t *UDPv5) lookupWorker(destNode *node, target enode.ID) ([]*node, error) { return nil, err } for _, n := range r { + if t.netrestrict != nil && !t.netrestrict.Contains(n.IP()) { + continue + } + if len(t.sentryNodes) > 0 && !has(t.sentryNodes, n.IP().String()) { + continue + } if n.ID() != t.Self().ID() { nodes.push(wrapNode(n), findnodeResultLimit) } @@ -810,6 +819,10 @@ func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*en // Apply some pre-checks to avoid sending invalid nodes. for _, n := range bn { + // Get rid of validator node out of the found node + if len(t.validatorNodes) > 0 && has(t.validatorNodes, n.IP().String()) { + continue + } // TODO livenessChecks > 1 if netutil.CheckRelayIP(rip, n.IP()) != nil { continue diff --git a/p2p/netutil/net.go b/p2p/netutil/net.go index d5da3c694f8e..09fda549162b 100644 --- a/p2p/netutil/net.go +++ b/p2p/netutil/net.go @@ -87,6 +87,21 @@ func ParseNetlist(s string) (*Netlist, error) { return &l, nil } +func ParseIPs(s string) []string { + ws := strings.NewReplacer(" ", "", "\n", "", "\t", "") + ips := strings.Split(ws.Replace(s), ",") + l := make([]string, 0) + for _, ip := range ips { + if ip == "" { + continue + } + if n := net.ParseIP(ip); n != nil { + l = append(l, n.String()) + } + } + return l +} + // MarshalTOML implements toml.MarshalerRec. func (l Netlist) MarshalTOML() interface{} { list := make([]string, 0, len(l)) diff --git a/p2p/server.go b/p2p/server.go index bc77ea146dfe..2b056389f30d 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -114,6 +114,16 @@ type Config struct { // allowed to connect, even above the peer limit. TrustedNodes []*enode.Node + // Broadcasting peers' info in the discovery mode can be ignored + // If this option is set to non-nil, the nodes which match one the the + // IPs contained in the list are not broadcasted. + ValidatorNodes []string `toml:",omitempty"` + + // Connectivity can be restricted to certain sentry nodes + // If this option is set to a non-nil, only nodes which match one of the + // IPs contained in the list are considered. + SentryNodes []string `toml:",omitempty"` + // Connectivity can be restricted to certain IP networks. // If this option is set to a non-nil value, only hosts which match one of the // IP networks contained in the list are considered. @@ -592,6 +602,7 @@ func (srv *Server) setupDiscovery() error { cfg := discover.Config{ PrivateKey: srv.PrivateKey, NetRestrict: srv.NetRestrict, + SentryNodes: srv.SentryNodes, Bootnodes: srv.BootstrapNodes, Unhandled: unhandled, Log: srv.log, @@ -609,6 +620,7 @@ func (srv *Server) setupDiscovery() error { cfg := discover.Config{ PrivateKey: srv.PrivateKey, NetRestrict: srv.NetRestrict, + SentryNodes: srv.SentryNodes, Bootnodes: srv.BootstrapNodesV5, Log: srv.log, } @@ -632,6 +644,7 @@ func (srv *Server) setupDialScheduler() { maxActiveDials: srv.MaxPendingPeers, log: srv.Logger, netRestrict: srv.NetRestrict, + sentryNodes: srv.SentryNodes, dialer: srv.Dialer, clock: srv.clock, } @@ -916,6 +929,10 @@ func (srv *Server) checkInboundConn(remoteIP net.IP) error { if srv.NetRestrict != nil && !srv.NetRestrict.Contains(remoteIP) { return fmt.Errorf("not in netrestrict list") } + // Reject connections that do not match sentry nodes. + if len(srv.SentryNodes) > 0 && !contains(srv.SentryNodes, remoteIP.String()) { + return fmt.Errorf("not in sentry nodes") + } // Reject Internet peers that try too often. now := srv.clock.Now() srv.inboundHistory.expire(now, nil) diff --git a/p2p/util.go b/p2p/util.go index 3c5f6b8508d5..034314ed1ecb 100644 --- a/p2p/util.go +++ b/p2p/util.go @@ -73,3 +73,14 @@ func (h *expHeap) Pop() interface{} { *h = old[0 : n-1] return x } + +// contains checks if a string is present in a slice +func contains(s []string, str string) bool { + for _, v := range s { + if v == str { + return true + } + } + + return false +} From a70c38672a6173caf8bfe94fee77e51d3af65857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 15 Jul 2022 22:03:32 +0700 Subject: [PATCH 02/18] p2p/discover: correct the netrestrict checking in UDPv5 --- p2p/discover/v5_udp.go | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 4bb6b53ff1a9..b0a750cf6f0b 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -312,12 +312,6 @@ func (t *UDPv5) lookupWorker(destNode *node, target enode.ID) ([]*node, error) { return nil, err } for _, n := range r { - if t.netrestrict != nil && !t.netrestrict.Contains(n.IP()) { - continue - } - if len(t.sentryNodes) > 0 && !has(t.sentryNodes, n.IP().String()) { - continue - } if n.ID() != t.Self().ID() { nodes.push(wrapNode(n), findnodeResultLimit) } @@ -416,6 +410,12 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s if err := netutil.CheckRelayIP(c.node.IP(), node.IP()); err != nil { return nil, err } + if t.netrestrict != nil && !t.netrestrict.Contains(node.IP()) { + return nil, errors.New("not contained in netrestrict list") + } + if len(t.sentryNodes) > 0 && !has(t.sentryNodes, node.IP().String()) { + return nil, errors.New("not contained in sentry nodes") + } if c.node.UDP() <= 1024 { return nil, errLowPort } @@ -819,10 +819,6 @@ func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*en // Apply some pre-checks to avoid sending invalid nodes. for _, n := range bn { - // Get rid of validator node out of the found node - if len(t.validatorNodes) > 0 && has(t.validatorNodes, n.IP().String()) { - continue - } // TODO livenessChecks > 1 if netutil.CheckRelayIP(rip, n.IP()) != nil { continue From 7fabf0bf3a09553c1c4ddccc8034749a410be7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 15 Jul 2022 22:18:44 +0700 Subject: [PATCH 03/18] get rid of validator node out of the found node in UDPv5 --- p2p/discover/v5_udp.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index b0a750cf6f0b..f2963c8b5e73 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -142,16 +142,17 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { cfg = cfg.withDefaults() t := &UDPv5{ // static fields - conn: conn, - localNode: ln, - db: ln.Database(), - netrestrict: cfg.NetRestrict, - sentryNodes: cfg.SentryNodes, - priv: cfg.PrivateKey, - log: cfg.Log, - validSchemes: cfg.ValidSchemes, - clock: cfg.Clock, - trhandlers: make(map[string]TalkRequestHandler), + conn: conn, + localNode: ln, + db: ln.Database(), + netrestrict: cfg.NetRestrict, + sentryNodes: cfg.SentryNodes, + validatorNodes: cfg.ValidatorNodes, + priv: cfg.PrivateKey, + log: cfg.Log, + validSchemes: cfg.ValidSchemes, + clock: cfg.Clock, + trhandlers: make(map[string]TalkRequestHandler), // channels into dispatch packetInCh: make(chan ReadPacket, 1), readNextCh: make(chan struct{}, 1), @@ -819,6 +820,10 @@ func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*en // Apply some pre-checks to avoid sending invalid nodes. for _, n := range bn { + // Get rid of validator node out of the found node + if len(t.validatorNodes) > 0 && has(t.validatorNodes, n.IP().String()) { + continue + } // TODO livenessChecks > 1 if netutil.CheckRelayIP(rip, n.IP()) != nil { continue From a8ffe544c8f8dc24cb0033ec27d4b791059b4833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Thu, 21 Jul 2022 19:11:27 +0700 Subject: [PATCH 04/18] refactor code and add ip restrict test for dial --- cmd/geth/main.go | 4 ++-- cmd/geth/usage.go | 4 ++-- cmd/utils/flags.go | 18 +++++++-------- p2p/dial.go | 8 +++---- p2p/dial_test.go | 35 ++++++++++++++++++++++++++++ p2p/discover/common.go | 16 ++++++------- p2p/discover/v4_udp.go | 34 +++++++++++++-------------- p2p/discover/v5_udp.go | 52 +++++++++++++++++++++--------------------- p2p/server.go | 18 +++++++-------- 9 files changed, 112 insertions(+), 77 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 78e953a34755..b7fb79021355 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -129,8 +129,8 @@ var ( utils.NoDiscoverFlag, utils.DiscoveryV5Flag, utils.NetrestrictFlag, - utils.SentryNodeFlag, - utils.ValidatorNodeFlag, + utils.IPrestrictFlag, + utils.PrivateNodeFlag, utils.NodeKeyFileFlag, utils.NodeKeyHexFlag, utils.DNSDiscoveryFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index f022aa6e7f75..74cf62a12fd7 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -169,8 +169,8 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.NoDiscoverFlag, utils.DiscoveryV5Flag, utils.NetrestrictFlag, - utils.SentryNodeFlag, - utils.ValidatorNodeFlag, + utils.IPrestrictFlag, + utils.PrivateNodeFlag, utils.NodeKeyFileFlag, utils.NodeKeyHexFlag, }, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 3a064f874a7d..877369c1f7b2 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -656,13 +656,13 @@ var ( Name: "netrestrict", Usage: "Restricts network communication to the given IP networks (CIDR masks)", } - SentryNodeFlag = cli.StringFlag{ - Name: "sentrynodes", + IPrestrictFlag = cli.StringFlag{ + Name: "iprestrict", Usage: "Restricts network communication to the given IP addresses", } - ValidatorNodeFlag = cli.StringFlag{ - Name: "validatornodes", - Usage: "Validator node list for sentry node", + PrivateNodeFlag = cli.StringFlag{ + Name: "privatenodes", + Usage: "Set list of private nodes IP that not be advertise to public network", } DNSDiscoveryFlag = cli.StringFlag{ Name: "discovery.dns", @@ -1205,12 +1205,12 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { cfg.NetRestrict = list } - if sentrynodes := ctx.GlobalString(SentryNodeFlag.Name); sentrynodes != "" { - cfg.SentryNodes = netutil.ParseIPs(sentrynodes) + if iprestrict := ctx.GlobalString(IPrestrictFlag.Name); iprestrict != "" { + cfg.IPRestrict = netutil.ParseIPs(iprestrict) } - if validatornodes := ctx.GlobalString(ValidatorNodeFlag.Name); validatornodes != "" { - cfg.ValidatorNodes = netutil.ParseIPs(validatornodes) + if privatenodes := ctx.GlobalString(PrivateNodeFlag.Name); privatenodes != "" { + cfg.PrivateNodes = netutil.ParseIPs(privatenodes) } if ctx.GlobalBool(DeveloperFlag.Name) || ctx.GlobalBool(CatalystFlag.Name) { diff --git a/p2p/dial.go b/p2p/dial.go index 463cb9596267..2b50afe4efcd 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -79,7 +79,7 @@ var ( errAlreadyListened = errors.New("already listened") errRecentlyDialed = errors.New("recently dialed") errNetRestrict = errors.New("not contained in netrestrict list") - errSentryNode = errors.New("not contained in sentry nodes") + errIPRestrict = errors.New("not contained in iprestrict list") errNoPort = errors.New("node does not provide TCP port") ) @@ -136,7 +136,7 @@ type dialConfig struct { maxDialPeers int // maximum number of dialed peers maxActiveDials int // maximum number of active dials netRestrict *netutil.Netlist // IP netrestrict list, disabled if nil - sentryNodes []string // IP address restrict list, disabled if nil + ipRestrict []string // IP address restrict list, disabled if nil resolver nodeResolver dialer NodeDialer log log.Logger @@ -407,8 +407,8 @@ func (d *dialScheduler) checkDial(n *enode.Node) error { if d.netRestrict != nil && !d.netRestrict.Contains(n.IP()) { return errNetRestrict } - if len(d.sentryNodes) > 0 && !contains(d.sentryNodes, n.IP().String()) { - return errSentryNode + if len(d.ipRestrict) > 0 && !contains(d.ipRestrict, n.IP().String()) { + return errIPRestrict } if d.history.contains(string(n.ID().Bytes())) { return errRecentlyDialed diff --git a/p2p/dial_test.go b/p2p/dial_test.go index cd8dedff1c6e..39954746c868 100644 --- a/p2p/dial_test.go +++ b/p2p/dial_test.go @@ -152,6 +152,41 @@ func TestDialSchedNetRestrict(t *testing.T) { }) } +func TestDialSchedIPRestrict(t *testing.T) { + t.Parallel() + + nodes := []*enode.Node{ + newNode(uintID(0x01), "127.0.0.1:30303"), + newNode(uintID(0x02), "127.0.0.2:30303"), + newNode(uintID(0x03), "127.0.0.3:30303"), + newNode(uintID(0x04), "127.0.0.4:30303"), + newNode(uintID(0x05), "127.0.2.5:30303"), + newNode(uintID(0x06), "127.0.2.6:30303"), + newNode(uintID(0x07), "127.0.2.7:30303"), + newNode(uintID(0x08), "127.0.2.8:30303"), + } + config := dialConfig{ + maxActiveDials: 10, + maxDialPeers: 10, + } + config.ipRestrict = []string{"127.0.0.1", "127.0.2.8"} + runDialTest(t, config, []dialTestRound{ + { + discovered: nodes, + wantNewDials: []*enode.Node{ + newNode(uintID(0x01), "127.0.0.1:30303"), + newNode(uintID(0x08), "127.0.2.8:30303"), + }, + }, + { + succeeded: []enode.ID{ + nodes[0].ID(), + nodes[7].ID(), + }, + }, + }) +} + // This test checks that static dials work and obey the limits. func TestDialSchedStaticDial(t *testing.T) { t.Parallel() diff --git a/p2p/discover/common.go b/p2p/discover/common.go index 2caba04c5ec3..cf5ca9713ebc 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -41,14 +41,14 @@ type Config struct { PrivateKey *ecdsa.PrivateKey // These settings are optional: - NetRestrict *netutil.Netlist // list of allowed IP networks - SentryNodes []string // list of allowed IPs - ValidatorNodes []string // list of validator IPs - Bootnodes []*enode.Node // list of bootstrap nodes - Unhandled chan<- ReadPacket // unhandled packets are sent on this channel - Log log.Logger // if set, log messages go here - ValidSchemes enr.IdentityScheme // allowed identity schemes - Clock mclock.Clock + NetRestrict *netutil.Netlist // list of allowed IP networks + IPRestrict []string // list of allowed IP addresses + PrivateNodes []string // list of private IPs + Bootnodes []*enode.Node // list of bootstrap nodes + Unhandled chan<- ReadPacket // unhandled packets are sent on this channel + Log log.Logger // if set, log messages go here + ValidSchemes enr.IdentityScheme // allowed identity schemes + Clock mclock.Clock } func (cfg Config) withDefaults() Config { diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index a953cb2406ae..60d45139e3f5 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -65,17 +65,17 @@ const ( // UDPv4 implements the v4 wire protocol. type UDPv4 struct { - conn UDPConn - log log.Logger - netrestrict *netutil.Netlist - sentryNodes []string - validatorNodes []string - priv *ecdsa.PrivateKey - localNode *enode.LocalNode - db *enode.DB - tab *Table - closeOnce sync.Once - wg sync.WaitGroup + conn UDPConn + log log.Logger + netrestrict *netutil.Netlist + iprestrict []string + privateNodes []string + priv *ecdsa.PrivateKey + localNode *enode.LocalNode + db *enode.DB + tab *Table + closeOnce sync.Once + wg sync.WaitGroup addReplyMatcher chan *replyMatcher gotreply chan reply @@ -135,8 +135,8 @@ func ListenV4(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) { conn: c, priv: cfg.PrivateKey, netrestrict: cfg.NetRestrict, - sentryNodes: cfg.SentryNodes, - validatorNodes: cfg.ValidatorNodes, + iprestrict: cfg.IPRestrict, + privateNodes: cfg.PrivateNodes, localNode: ln, db: ln.Database(), gotreply: make(chan reply), @@ -589,8 +589,8 @@ func (t *UDPv4) nodeFromRPC(sender *net.UDPAddr, rn v4wire.Node) (*node, error) if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) { return nil, errors.New("not contained in netrestrict list") } - if len(t.sentryNodes) > 0 && !has(t.sentryNodes, rn.IP.String()) { - return nil, errors.New("not contained in sentry nodes") + if len(t.iprestrict) > 0 && !has(t.iprestrict, rn.IP.String()) { + return nil, errors.New("not contained in iprestrict list") } key, err := v4wire.DecodePubkey(crypto.S256(), rn.ID) if err != nil { @@ -735,8 +735,8 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno p := v4wire.Neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} var sent bool for _, n := range closest { - // Get rid of validator node out of the found node - if len(t.validatorNodes) > 0 && has(t.validatorNodes, n.IP().String()) { + // Don't advertise the private nodes + if len(t.privateNodes) > 0 && has(t.privateNodes, n.IP().String()) { continue } if netutil.CheckRelayIP(from.IP, n.IP()) == nil { diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index f2963c8b5e73..adce0f8c7be4 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -62,17 +62,17 @@ type codecV5 interface { // UDPv5 is the implementation of protocol version 5. type UDPv5 struct { // static fields - conn UDPConn - tab *Table - netrestrict *netutil.Netlist - sentryNodes []string - validatorNodes []string - priv *ecdsa.PrivateKey - localNode *enode.LocalNode - db *enode.DB - log log.Logger - clock mclock.Clock - validSchemes enr.IdentityScheme + conn UDPConn + tab *Table + netrestrict *netutil.Netlist + iprestrict []string + privateNodes []string + priv *ecdsa.PrivateKey + localNode *enode.LocalNode + db *enode.DB + log log.Logger + clock mclock.Clock + validSchemes enr.IdentityScheme // talkreq handler registry trlock sync.Mutex @@ -142,17 +142,17 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { cfg = cfg.withDefaults() t := &UDPv5{ // static fields - conn: conn, - localNode: ln, - db: ln.Database(), - netrestrict: cfg.NetRestrict, - sentryNodes: cfg.SentryNodes, - validatorNodes: cfg.ValidatorNodes, - priv: cfg.PrivateKey, - log: cfg.Log, - validSchemes: cfg.ValidSchemes, - clock: cfg.Clock, - trhandlers: make(map[string]TalkRequestHandler), + conn: conn, + localNode: ln, + db: ln.Database(), + netrestrict: cfg.NetRestrict, + iprestrict: cfg.IPRestrict, + privateNodes: cfg.PrivateNodes, + priv: cfg.PrivateKey, + log: cfg.Log, + validSchemes: cfg.ValidSchemes, + clock: cfg.Clock, + trhandlers: make(map[string]TalkRequestHandler), // channels into dispatch packetInCh: make(chan ReadPacket, 1), readNextCh: make(chan struct{}, 1), @@ -414,8 +414,8 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s if t.netrestrict != nil && !t.netrestrict.Contains(node.IP()) { return nil, errors.New("not contained in netrestrict list") } - if len(t.sentryNodes) > 0 && !has(t.sentryNodes, node.IP().String()) { - return nil, errors.New("not contained in sentry nodes") + if len(t.iprestrict) > 0 && !has(t.iprestrict, node.IP().String()) { + return nil, errors.New("not contained in iprestrict list") } if c.node.UDP() <= 1024 { return nil, errLowPort @@ -820,8 +820,8 @@ func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*en // Apply some pre-checks to avoid sending invalid nodes. for _, n := range bn { - // Get rid of validator node out of the found node - if len(t.validatorNodes) > 0 && has(t.validatorNodes, n.IP().String()) { + // Don't advertise the private nodes + if len(t.privateNodes) > 0 && has(t.privateNodes, n.IP().String()) { continue } // TODO livenessChecks > 1 diff --git a/p2p/server.go b/p2p/server.go index 2b056389f30d..6ffe5ff0a590 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -117,12 +117,12 @@ type Config struct { // Broadcasting peers' info in the discovery mode can be ignored // If this option is set to non-nil, the nodes which match one the the // IPs contained in the list are not broadcasted. - ValidatorNodes []string `toml:",omitempty"` + PrivateNodes []string `toml:",omitempty"` - // Connectivity can be restricted to certain sentry nodes + // Connectivity can be restricted to certain IP addresses // If this option is set to a non-nil, only nodes which match one of the // IPs contained in the list are considered. - SentryNodes []string `toml:",omitempty"` + IPRestrict []string `toml:",omitempty"` // Connectivity can be restricted to certain IP networks. // If this option is set to a non-nil value, only hosts which match one of the @@ -602,7 +602,7 @@ func (srv *Server) setupDiscovery() error { cfg := discover.Config{ PrivateKey: srv.PrivateKey, NetRestrict: srv.NetRestrict, - SentryNodes: srv.SentryNodes, + IPRestrict: srv.IPRestrict, Bootnodes: srv.BootstrapNodes, Unhandled: unhandled, Log: srv.log, @@ -620,7 +620,7 @@ func (srv *Server) setupDiscovery() error { cfg := discover.Config{ PrivateKey: srv.PrivateKey, NetRestrict: srv.NetRestrict, - SentryNodes: srv.SentryNodes, + IPRestrict: srv.IPRestrict, Bootnodes: srv.BootstrapNodesV5, Log: srv.log, } @@ -644,7 +644,7 @@ func (srv *Server) setupDialScheduler() { maxActiveDials: srv.MaxPendingPeers, log: srv.Logger, netRestrict: srv.NetRestrict, - sentryNodes: srv.SentryNodes, + ipRestrict: srv.IPRestrict, dialer: srv.Dialer, clock: srv.clock, } @@ -929,9 +929,9 @@ func (srv *Server) checkInboundConn(remoteIP net.IP) error { if srv.NetRestrict != nil && !srv.NetRestrict.Contains(remoteIP) { return fmt.Errorf("not in netrestrict list") } - // Reject connections that do not match sentry nodes. - if len(srv.SentryNodes) > 0 && !contains(srv.SentryNodes, remoteIP.String()) { - return fmt.Errorf("not in sentry nodes") + // Reject connections that do not match IPRestrict. + if len(srv.IPRestrict) > 0 && !contains(srv.IPRestrict, remoteIP.String()) { + return fmt.Errorf("not in iprestrict list") } // Reject Internet peers that try too often. now := srv.clock.Now() From 210582fd57980857e1e638e38f33f91b479e6189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 22 Jul 2022 11:32:00 +0700 Subject: [PATCH 05/18] allow update iprestrict/private ip via admin console --- internal/web3ext/web3ext.go | 20 ++++++++++++ node/api.go | 55 +++++++++++++++++++++++++++++++ p2p/discover/v4_udp.go | 16 ++++++++++ p2p/server.go | 64 +++++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 62cc7dbfe79d..0a2f6d6f1c34 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -141,6 +141,26 @@ web3._extend({ call: 'admin_removeTrustedPeer', params: 1 }), + new web3._extend.Method({ + name: 'addPrivateNode', + call: 'admin_addPrivateNode', + params: 1 + }), + new web3._extend.Method({ + name: 'removePrivateNode', + call: 'admin_removePrivateNode', + params: 1 + }), + new web3._extend.Method({ + name: 'addIPRestrict', + call: 'admin_addIPRestrict', + params: 1 + }), + new web3._extend.Method({ + name: 'removeIPRestrict', + call: 'admin_removeIPRestrict', + params: 1 + }), new web3._extend.Method({ name: 'exportChain', call: 'admin_exportChain', diff --git a/node/api.go b/node/api.go index be20b89d95c0..9e488a8af6cc 100644 --- a/node/api.go +++ b/node/api.go @@ -19,6 +19,7 @@ package node import ( "context" "fmt" + "net" "strings" "github.com/ethereum/go-ethereum/common/hexutil" @@ -125,6 +126,60 @@ func (api *privateAdminAPI) RemoveTrustedPeer(url string) (bool, error) { return true, nil } +// AddIPRestrict allow an ip to connect +func (api *privateAdminAPI) AddIPRestrict(ip string) (bool, error) { + // Make sure the server is running, fail otherwise + server := api.node.Server() + if server == nil { + return false, ErrNodeStopped + } + if node := net.ParseIP(ip); node == nil { + return false, fmt.Errorf("invalid ip address: %v", ip) + } + server.AddIPRestrict(ip) + return true, nil +} + +// RemoveIPRestrict remove ip from the restrict allow ip list +func (api *privateAdminAPI) RemoveIPRestrict(ip string) (bool, error) { + // Make sure the server is running, fail otherwise + server := api.node.Server() + if server == nil { + return false, ErrNodeStopped + } + if node := net.ParseIP(ip); node == nil { + return false, fmt.Errorf("invalid ip address: %v", ip) + } + server.RemoveIPRestrict(ip) + return true, nil +} + +func (api *privateAdminAPI) AddPrivateNode(ip string) (bool, error) { + // Make sure the server is running, fail otherwise + server := api.node.Server() + if server == nil { + return false, ErrNodeStopped + } + if node := net.ParseIP(ip); node == nil { + return false, fmt.Errorf("invalid node address: %v", ip) + } + server.AddPrivateNode(ip) + return true, nil +} + +func (api *privateAdminAPI) RemovePrivateNode(ip string) (bool, error) { + // Make sure the server is running, fail otherwise + server := api.node.Server() + if server == nil { + return false, ErrNodeStopped + } + if node := net.ParseIP(ip); node == nil { + return false, fmt.Errorf("invalid node address: %v", ip) + } + server.RemovePrivateNode(ip) + return true, nil +} + // PeerEvents creates an RPC subscription which receives peer events from the // node's p2p.Server func (api *privateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) { diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 60d45139e3f5..0643b9ada511 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -204,6 +204,22 @@ func (t *UDPv4) Resolve(n *enode.Node) *enode.Node { return n } +func (t *UDPv4) UpdateIPRestrict(restricts map[string]bool) { + ips := []string{} + for ip, _ := range restricts { + ips = append(ips, ip) + } + t.iprestrict = ips +} + +func (t *UDPv4) UpdatePrivateNodes(privates map[string]bool) { + ips := []string{} + for ip, _ := range privates { + ips = append(ips, ip) + } + t.iprestrict = ips +} + func (t *UDPv4) ourEndpoint() v4wire.Endpoint { n := t.Self() a := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} diff --git a/p2p/server.go b/p2p/server.go index 6ffe5ff0a590..ca2f01378333 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -199,6 +199,10 @@ type Server struct { quit chan struct{} addtrusted chan *enode.Node removetrusted chan *enode.Node + addiprestrict chan string + removeiprestrict chan string + addprivatenode chan string + removeprivatenode chan string peerOp chan peerOpFunc peerOpDone chan struct{} delpeer chan peerDrop @@ -380,6 +384,34 @@ func (srv *Server) RemoveTrustedPeer(node *enode.Node) { } } +func (srv *Server) AddIPRestrict(ip string) { + select { + case srv.addiprestrict <- ip: + case <-srv.quit: + } +} + +func (srv *Server) RemoveIPRestrict(ip string) { + select { + case srv.removeiprestrict <- ip: + case <-srv.quit: + } +} + +func (srv *Server) AddPrivateNode(node string) { + select { + case srv.addprivatenode <- node: + case <-srv.quit: + } +} + +func (srv *Server) RemovePrivateNode(node string) { + select { + case srv.removeprivatenode <- node: + case <-srv.quit: + } +} + // SubscribeEvents subscribes the given channel to peer events func (srv *Server) SubscribeEvents(ch chan *PeerEvent) event.Subscription { return srv.peerFeed.Subscribe(ch) @@ -477,6 +509,10 @@ func (srv *Server) Start() (err error) { srv.checkpointAddPeer = make(chan *conn) srv.addtrusted = make(chan *enode.Node) srv.removetrusted = make(chan *enode.Node) + srv.addiprestrict = make(chan string) + srv.removeiprestrict = make(chan string) + srv.addprivatenode = make(chan string) + srv.removeprivatenode = make(chan string) srv.peerOp = make(chan peerOpFunc) srv.peerOpDone = make(chan struct{}) @@ -726,12 +762,20 @@ func (srv *Server) run() { peers = make(map[enode.ID]*Peer) inboundCount = 0 trusted = make(map[enode.ID]bool, len(srv.TrustedNodes)) + privates = make(map[string]bool, len(srv.PrivateNodes)) + restricts = make(map[string]bool, len(srv.IPRestrict)) ) // Put trusted nodes into a map to speed up checks. // Trusted peers are loaded on startup or added via AddTrustedPeer RPC. for _, n := range srv.TrustedNodes { trusted[n.ID()] = true } + for _, n := range srv.PrivateNodes { + privates[n] = true + } + for _, ip := range srv.IPRestrict { + restricts[ip] = true + } running: for { @@ -758,6 +802,26 @@ running: p.rw.set(trustedConn, false) } + case ip := <-srv.addiprestrict: + srv.log.Warn("Adding ip restrict", "ip", ip) + restricts[ip] = true + srv.ntab.UpdateIPRestrict(restricts) + + case ip := <-srv.removeiprestrict: + srv.log.Warn("Removing ip restrict", "ip", ip) + delete(restricts, ip) + srv.ntab.UpdateIPRestrict(restricts) + + case p := <-srv.addprivatenode: + srv.log.Warn("Adding private node", "node", p) + privates[p] = true + srv.ntab.UpdatePrivateNodes(privates) + + case p := <-srv.removeprivatenode: + srv.log.Warn("Removing private node", "node", p) + delete(privates, p) + srv.ntab.UpdatePrivateNodes(privates) + case op := <-srv.peerOp: // This channel is used by Peers and PeerCount. op(peers) From e4a94df59774bc98a33e2433baec7834aaf46385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 22 Jul 2022 12:07:42 +0700 Subject: [PATCH 06/18] also remove the peer if it's not in the updated ip restrict --- node/api.go | 2 ++ p2p/server.go | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/node/api.go b/node/api.go index 9e488a8af6cc..de9f22cc25e4 100644 --- a/node/api.go +++ b/node/api.go @@ -154,6 +154,7 @@ func (api *privateAdminAPI) RemoveIPRestrict(ip string) (bool, error) { return true, nil } +// AddPrivateNode add an ip not to be advertise to the other peers func (api *privateAdminAPI) AddPrivateNode(ip string) (bool, error) { // Make sure the server is running, fail otherwise server := api.node.Server() @@ -167,6 +168,7 @@ func (api *privateAdminAPI) AddPrivateNode(ip string) (bool, error) { return true, nil } +// RemovePrivateNode remove ip out of non-advertise ip list func (api *privateAdminAPI) RemovePrivateNode(ip string) (bool, error) { // Make sure the server is running, fail otherwise server := api.node.Server() diff --git a/p2p/server.go b/p2p/server.go index ca2f01378333..a71b2dc539e1 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -812,6 +812,13 @@ running: delete(restricts, ip) srv.ntab.UpdateIPRestrict(restricts) + for _, n := range srv.StaticNodes { + if n.IP().String() == ip { + srv.dialsched.removeStatic(n) + srv.RemoveTrustedPeer(n) + } + } + case p := <-srv.addprivatenode: srv.log.Warn("Adding private node", "node", p) privates[p] = true From bdf7ed4ce0da30a5162f0db4685f8ad25631b92e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 22 Jul 2022 14:49:34 +0700 Subject: [PATCH 07/18] update peer set when setting ip restrict from nil --- p2p/discover/v4_udp.go | 6 +----- p2p/server.go | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 0643b9ada511..7dc72811ecd5 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -204,11 +204,7 @@ func (t *UDPv4) Resolve(n *enode.Node) *enode.Node { return n } -func (t *UDPv4) UpdateIPRestrict(restricts map[string]bool) { - ips := []string{} - for ip, _ := range restricts { - ips = append(ips, ip) - } +func (t *UDPv4) UpdateIPRestrict(ips []string) { t.iprestrict = ips } diff --git a/p2p/server.go b/p2p/server.go index a71b2dc539e1..86ed36b3cfff 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -804,13 +804,35 @@ running: case ip := <-srv.addiprestrict: srv.log.Warn("Adding ip restrict", "ip", ip) + + // If it's the first time to activate the ip restrict, + // then remove all the current peers that not in the ip restrict list + if len(restricts) == 0 { + for _, n := range srv.StaticNodes { + if n.IP().String() != ip { + srv.dialsched.removeStatic(n) + srv.RemoveTrustedPeer(n) + } + } + } + restricts[ip] = true - srv.ntab.UpdateIPRestrict(restricts) + ips := []string{} + for ip, _ := range restricts { + ips = append(ips, ip) + } + srv.IPRestrict = ips + srv.ntab.UpdateIPRestrict(ips) case ip := <-srv.removeiprestrict: srv.log.Warn("Removing ip restrict", "ip", ip) delete(restricts, ip) - srv.ntab.UpdateIPRestrict(restricts) + ips := []string{} + for ip, _ := range restricts { + ips = append(ips, ip) + } + srv.IPRestrict = ips + srv.ntab.UpdateIPRestrict(ips) for _, n := range srv.StaticNodes { if n.IP().String() == ip { From 3ceffaa02e3306855b50619e186f76ded2b66a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 22 Jul 2022 15:23:53 +0700 Subject: [PATCH 08/18] add admin property to tracking iprestrict and private nodes on console --- internal/web3ext/web3ext.go | 8 ++++++++ node/api.go | 16 ++++++++++++++++ p2p/discover/v4_udp.go | 8 ++------ p2p/server.go | 22 ++++++++++++++++------ 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 0a2f6d6f1c34..29c0c549f340 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -219,6 +219,14 @@ web3._extend({ name: 'peers', getter: 'admin_peers' }), + new web3._extend.Property({ + name: 'privateNodes', + getter: 'admin_privateNodes' + }), + new web3._extend.Property({ + name: 'iprestrict', + getter: 'admin_iprestrict' + }), new web3._extend.Property({ name: 'datadir', getter: 'admin_datadir' diff --git a/node/api.go b/node/api.go index de9f22cc25e4..7c566f601668 100644 --- a/node/api.go +++ b/node/api.go @@ -383,6 +383,22 @@ func (api *publicAdminAPI) Datadir() string { return api.node.DataDir() } +func (api *publicAdminAPI) PrivateNodes() ([]string, error) { + server := api.node.Server() + if server == nil { + return nil, ErrNodeStopped + } + return server.PrivateNodes, nil +} + +func (api *publicAdminAPI) Iprestrict() ([]string, error) { + server := api.node.Server() + if server == nil { + return nil, ErrNodeStopped + } + return server.IPRestrict, nil +} + // publicWeb3API offers helper utils type publicWeb3API struct { stack *Node diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 7dc72811ecd5..9e8b3823ac36 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -208,12 +208,8 @@ func (t *UDPv4) UpdateIPRestrict(ips []string) { t.iprestrict = ips } -func (t *UDPv4) UpdatePrivateNodes(privates map[string]bool) { - ips := []string{} - for ip, _ := range privates { - ips = append(ips, ip) - } - t.iprestrict = ips +func (t *UDPv4) UpdatePrivateNodes(ips []string) { + t.privateNodes = ips } func (t *UDPv4) ourEndpoint() v4wire.Endpoint { diff --git a/p2p/server.go b/p2p/server.go index 86ed36b3cfff..5ccdc0cc69f2 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -803,7 +803,7 @@ running: } case ip := <-srv.addiprestrict: - srv.log.Warn("Adding ip restrict", "ip", ip) + srv.log.Trace("Adding ip restrict", "ip", ip) // If it's the first time to activate the ip restrict, // then remove all the current peers that not in the ip restrict list @@ -825,7 +825,7 @@ running: srv.ntab.UpdateIPRestrict(ips) case ip := <-srv.removeiprestrict: - srv.log.Warn("Removing ip restrict", "ip", ip) + srv.log.Trace("Removing ip restrict", "ip", ip) delete(restricts, ip) ips := []string{} for ip, _ := range restricts { @@ -842,14 +842,24 @@ running: } case p := <-srv.addprivatenode: - srv.log.Warn("Adding private node", "node", p) + srv.log.Trace("Adding private node", "node", p) privates[p] = true - srv.ntab.UpdatePrivateNodes(privates) + ips := []string{} + for ip, _ := range privates { + ips = append(ips, ip) + } + srv.PrivateNodes = ips + srv.ntab.UpdatePrivateNodes(ips) case p := <-srv.removeprivatenode: - srv.log.Warn("Removing private node", "node", p) + srv.log.Trace("Removing private node", "node", p) delete(privates, p) - srv.ntab.UpdatePrivateNodes(privates) + ips := []string{} + for ip, _ := range privates { + ips = append(ips, ip) + } + srv.PrivateNodes = ips + srv.ntab.UpdatePrivateNodes(ips) case op := <-srv.peerOp: // This channel is used by Peers and PeerCount. From e578c33af27925151f9147410d95ad4a84dee772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 22 Jul 2022 16:40:47 +0700 Subject: [PATCH 09/18] should remove node from peers, not from static nodes --- p2p/dial.go | 6 +++--- p2p/server.go | 14 ++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/p2p/dial.go b/p2p/dial.go index 2b50afe4efcd..d20b7f5e35ce 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -109,7 +109,7 @@ type dialScheduler struct { // Everything below here belongs to loop and // should only be accessed by code on the loop goroutine. dialing map[enode.ID]*dialTask // active tasks - peers map[enode.ID]connFlag // all connected peers + peers map[enode.ID]*conn // all connected peers dialPeers int // current number of dialed peers // The static map tracks all static dial tasks. The subset of usable static dial tasks @@ -169,7 +169,7 @@ func newDialScheduler(config dialConfig, it enode.Iterator, setupFunc dialSetupF setupFunc: setupFunc, dialing: make(map[enode.ID]*dialTask), static: make(map[enode.ID]*dialTask), - peers: make(map[enode.ID]connFlag), + peers: make(map[enode.ID]*conn), doneCh: make(chan *dialTask), nodesIn: make(chan *enode.Node), addStaticCh: make(chan *enode.Node), @@ -262,7 +262,7 @@ loop: d.dialPeers++ } id := c.node.ID() - d.peers[id] = c.flags + d.peers[id] = c // Remove from static pool because the node is now connected. task := d.static[id] if task != nil && task.staticPoolIndex >= 0 { diff --git a/p2p/server.go b/p2p/server.go index 5ccdc0cc69f2..a10f1709d74d 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -808,10 +808,9 @@ running: // If it's the first time to activate the ip restrict, // then remove all the current peers that not in the ip restrict list if len(restricts) == 0 { - for _, n := range srv.StaticNodes { - if n.IP().String() != ip { - srv.dialsched.removeStatic(n) - srv.RemoveTrustedPeer(n) + for _, c := range srv.dialsched.peers { + if c.node.IP().String() != ip { + srv.RemovePeer(c.node) } } } @@ -834,10 +833,9 @@ running: srv.IPRestrict = ips srv.ntab.UpdateIPRestrict(ips) - for _, n := range srv.StaticNodes { - if n.IP().String() == ip { - srv.dialsched.removeStatic(n) - srv.RemoveTrustedPeer(n) + for _, c := range srv.dialsched.peers { + if c.node.IP().String() == ip { + srv.RemovePeer(c.node) } } From 9c1f89952911dab7bf426467fd4c26a3b83e66a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 22 Jul 2022 17:25:05 +0700 Subject: [PATCH 10/18] p2p hanlde will manage the peers itself --- p2p/server.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/p2p/server.go b/p2p/server.go index a10f1709d74d..7eb4d27203c7 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -805,16 +805,6 @@ running: case ip := <-srv.addiprestrict: srv.log.Trace("Adding ip restrict", "ip", ip) - // If it's the first time to activate the ip restrict, - // then remove all the current peers that not in the ip restrict list - if len(restricts) == 0 { - for _, c := range srv.dialsched.peers { - if c.node.IP().String() != ip { - srv.RemovePeer(c.node) - } - } - } - restricts[ip] = true ips := []string{} for ip, _ := range restricts { @@ -833,12 +823,6 @@ running: srv.IPRestrict = ips srv.ntab.UpdateIPRestrict(ips) - for _, c := range srv.dialsched.peers { - if c.node.IP().String() == ip { - srv.RemovePeer(c.node) - } - } - case p := <-srv.addprivatenode: srv.log.Trace("Adding private node", "node", p) privates[p] = true From e9709111b8fd2d7c62bac68352bddc167c0c806c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 22 Jul 2022 17:45:32 +0700 Subject: [PATCH 11/18] allow node to handle peers via dial config --- p2p/dial.go | 55 +++++++++++++++++++++++++++++++-------------------- p2p/server.go | 2 ++ 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/p2p/dial.go b/p2p/dial.go index d20b7f5e35ce..fab641356b11 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -95,16 +95,17 @@ var ( // type dialScheduler struct { dialConfig - setupFunc dialSetupFunc - wg sync.WaitGroup - cancel context.CancelFunc - ctx context.Context - nodesIn chan *enode.Node - doneCh chan *dialTask - addStaticCh chan *enode.Node - remStaticCh chan *enode.Node - addPeerCh chan *conn - remPeerCh chan *conn + setupFunc dialSetupFunc + wg sync.WaitGroup + cancel context.CancelFunc + ctx context.Context + nodesIn chan *enode.Node + doneCh chan *dialTask + addStaticCh chan *enode.Node + remStaticCh chan *enode.Node + addPeerCh chan *conn + remPeerCh chan *conn + updateIPRestrictCh chan []string // Everything below here belongs to loop and // should only be accessed by code on the loop goroutine. @@ -165,17 +166,18 @@ func (cfg dialConfig) withDefaults() dialConfig { func newDialScheduler(config dialConfig, it enode.Iterator, setupFunc dialSetupFunc) *dialScheduler { d := &dialScheduler{ - dialConfig: config.withDefaults(), - setupFunc: setupFunc, - dialing: make(map[enode.ID]*dialTask), - static: make(map[enode.ID]*dialTask), - peers: make(map[enode.ID]*conn), - doneCh: make(chan *dialTask), - nodesIn: make(chan *enode.Node), - addStaticCh: make(chan *enode.Node), - remStaticCh: make(chan *enode.Node), - addPeerCh: make(chan *conn), - remPeerCh: make(chan *conn), + dialConfig: config.withDefaults(), + setupFunc: setupFunc, + dialing: make(map[enode.ID]*dialTask), + static: make(map[enode.ID]*dialTask), + peers: make(map[enode.ID]*conn), + doneCh: make(chan *dialTask), + nodesIn: make(chan *enode.Node), + addStaticCh: make(chan *enode.Node), + remStaticCh: make(chan *enode.Node), + addPeerCh: make(chan *conn), + remPeerCh: make(chan *conn), + updateIPRestrictCh: make(chan []string), } d.lastStatsLog = d.clock.Now() d.ctx, d.cancel = context.WithCancel(context.Background()) @@ -191,6 +193,13 @@ func (d *dialScheduler) stop() { d.wg.Wait() } +func (d *dialScheduler) updateIPRestrict(s []string) { + select { + case d.updateIPRestrictCh <- s: + case <-d.ctx.Done(): + } +} + // addStatic adds a static dial candidate. func (d *dialScheduler) addStatic(n *enode.Node) { select { @@ -277,6 +286,10 @@ loop: delete(d.peers, c.node.ID()) d.updateStaticPool(c.node.ID()) + case ips := <-d.updateIPRestrictCh: + d.log.Trace("Update ip restrict", "ips", ips) + d.ipRestrict = ips + case node := <-d.addStaticCh: id := node.ID() _, exists := d.static[id] diff --git a/p2p/server.go b/p2p/server.go index 7eb4d27203c7..da9a0efbad94 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -811,6 +811,7 @@ running: ips = append(ips, ip) } srv.IPRestrict = ips + srv.dialsched.updateIPRestrict(ips) srv.ntab.UpdateIPRestrict(ips) case ip := <-srv.removeiprestrict: @@ -821,6 +822,7 @@ running: ips = append(ips, ip) } srv.IPRestrict = ips + srv.dialsched.updateIPRestrict(ips) srv.ntab.UpdateIPRestrict(ips) case p := <-srv.addprivatenode: From 8141e1d7fe12cbcf4e8243be5e058d3135fffb42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 22 Jul 2022 20:55:11 +0700 Subject: [PATCH 12/18] try to call dialsched peer removed after ip restrict be updated --- p2p/server.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/p2p/server.go b/p2p/server.go index da9a0efbad94..ddfa92efa6f7 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -805,6 +805,20 @@ running: case ip := <-srv.addiprestrict: srv.log.Trace("Adding ip restrict", "ip", ip) + if len(restricts) == 0 { + for _, c := range srv.dialsched.peers { + if c.node.IP().String() != ip { + if p, ok := peers[c.node.ID()]; ok { + delete(peers, c.node.ID()) + srv.dialsched.peerRemoved(c) + if p.Inbound() { + inboundCount-- + } + } + } + } + } + restricts[ip] = true ips := []string{} for ip, _ := range restricts { @@ -824,6 +838,17 @@ running: srv.IPRestrict = ips srv.dialsched.updateIPRestrict(ips) srv.ntab.UpdateIPRestrict(ips) + for _, c := range srv.dialsched.peers { + if c.node.IP().String() == ip { + if p, ok := peers[c.node.ID()]; ok { + delete(peers, c.node.ID()) + srv.dialsched.peerRemoved(c) + if p.Inbound() { + inboundCount-- + } + } + } + } case p := <-srv.addprivatenode: srv.log.Trace("Adding private node", "node", p) From fb92b6c1d3a045d1c19dfb1b4b15dd0b3aa10f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 22 Jul 2022 21:47:37 +0700 Subject: [PATCH 13/18] only remove the peers when ip restrict is not-nil --- p2p/server.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/p2p/server.go b/p2p/server.go index ddfa92efa6f7..92a3efb0d00b 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -838,13 +838,15 @@ running: srv.IPRestrict = ips srv.dialsched.updateIPRestrict(ips) srv.ntab.UpdateIPRestrict(ips) - for _, c := range srv.dialsched.peers { - if c.node.IP().String() == ip { - if p, ok := peers[c.node.ID()]; ok { - delete(peers, c.node.ID()) - srv.dialsched.peerRemoved(c) - if p.Inbound() { - inboundCount-- + if len(restricts) > 0 { + for _, c := range srv.dialsched.peers { + if c.node.IP().String() == ip { + if p, ok := peers[c.node.ID()]; ok { + delete(peers, c.node.ID()) + srv.dialsched.peerRemoved(c) + if p.Inbound() { + inboundCount-- + } } } } From 08324f096dbb442ad4f8e29b1945cc9f2642276c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Tue, 26 Jul 2022 17:09:55 +0700 Subject: [PATCH 14/18] remove all new admin console methods --- internal/web3ext/web3ext.go | 20 ------- node/api.go | 57 ------------------- p2p/dial.go | 59 ++++++++------------ p2p/discover/v4_udp.go | 8 --- p2p/server.go | 106 ------------------------------------ 5 files changed, 23 insertions(+), 227 deletions(-) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 29c0c549f340..09eb0b97ddb6 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -141,26 +141,6 @@ web3._extend({ call: 'admin_removeTrustedPeer', params: 1 }), - new web3._extend.Method({ - name: 'addPrivateNode', - call: 'admin_addPrivateNode', - params: 1 - }), - new web3._extend.Method({ - name: 'removePrivateNode', - call: 'admin_removePrivateNode', - params: 1 - }), - new web3._extend.Method({ - name: 'addIPRestrict', - call: 'admin_addIPRestrict', - params: 1 - }), - new web3._extend.Method({ - name: 'removeIPRestrict', - call: 'admin_removeIPRestrict', - params: 1 - }), new web3._extend.Method({ name: 'exportChain', call: 'admin_exportChain', diff --git a/node/api.go b/node/api.go index 7c566f601668..3f90cb4b6e0b 100644 --- a/node/api.go +++ b/node/api.go @@ -19,7 +19,6 @@ package node import ( "context" "fmt" - "net" "strings" "github.com/ethereum/go-ethereum/common/hexutil" @@ -126,62 +125,6 @@ func (api *privateAdminAPI) RemoveTrustedPeer(url string) (bool, error) { return true, nil } -// AddIPRestrict allow an ip to connect -func (api *privateAdminAPI) AddIPRestrict(ip string) (bool, error) { - // Make sure the server is running, fail otherwise - server := api.node.Server() - if server == nil { - return false, ErrNodeStopped - } - if node := net.ParseIP(ip); node == nil { - return false, fmt.Errorf("invalid ip address: %v", ip) - } - server.AddIPRestrict(ip) - return true, nil -} - -// RemoveIPRestrict remove ip from the restrict allow ip list -func (api *privateAdminAPI) RemoveIPRestrict(ip string) (bool, error) { - // Make sure the server is running, fail otherwise - server := api.node.Server() - if server == nil { - return false, ErrNodeStopped - } - if node := net.ParseIP(ip); node == nil { - return false, fmt.Errorf("invalid ip address: %v", ip) - } - server.RemoveIPRestrict(ip) - return true, nil -} - -// AddPrivateNode add an ip not to be advertise to the other peers -func (api *privateAdminAPI) AddPrivateNode(ip string) (bool, error) { - // Make sure the server is running, fail otherwise - server := api.node.Server() - if server == nil { - return false, ErrNodeStopped - } - if node := net.ParseIP(ip); node == nil { - return false, fmt.Errorf("invalid node address: %v", ip) - } - server.AddPrivateNode(ip) - return true, nil -} - -// RemovePrivateNode remove ip out of non-advertise ip list -func (api *privateAdminAPI) RemovePrivateNode(ip string) (bool, error) { - // Make sure the server is running, fail otherwise - server := api.node.Server() - if server == nil { - return false, ErrNodeStopped - } - if node := net.ParseIP(ip); node == nil { - return false, fmt.Errorf("invalid node address: %v", ip) - } - server.RemovePrivateNode(ip) - return true, nil -} - // PeerEvents creates an RPC subscription which receives peer events from the // node's p2p.Server func (api *privateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) { diff --git a/p2p/dial.go b/p2p/dial.go index fab641356b11..2b50afe4efcd 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -95,22 +95,21 @@ var ( // type dialScheduler struct { dialConfig - setupFunc dialSetupFunc - wg sync.WaitGroup - cancel context.CancelFunc - ctx context.Context - nodesIn chan *enode.Node - doneCh chan *dialTask - addStaticCh chan *enode.Node - remStaticCh chan *enode.Node - addPeerCh chan *conn - remPeerCh chan *conn - updateIPRestrictCh chan []string + setupFunc dialSetupFunc + wg sync.WaitGroup + cancel context.CancelFunc + ctx context.Context + nodesIn chan *enode.Node + doneCh chan *dialTask + addStaticCh chan *enode.Node + remStaticCh chan *enode.Node + addPeerCh chan *conn + remPeerCh chan *conn // Everything below here belongs to loop and // should only be accessed by code on the loop goroutine. dialing map[enode.ID]*dialTask // active tasks - peers map[enode.ID]*conn // all connected peers + peers map[enode.ID]connFlag // all connected peers dialPeers int // current number of dialed peers // The static map tracks all static dial tasks. The subset of usable static dial tasks @@ -166,18 +165,17 @@ func (cfg dialConfig) withDefaults() dialConfig { func newDialScheduler(config dialConfig, it enode.Iterator, setupFunc dialSetupFunc) *dialScheduler { d := &dialScheduler{ - dialConfig: config.withDefaults(), - setupFunc: setupFunc, - dialing: make(map[enode.ID]*dialTask), - static: make(map[enode.ID]*dialTask), - peers: make(map[enode.ID]*conn), - doneCh: make(chan *dialTask), - nodesIn: make(chan *enode.Node), - addStaticCh: make(chan *enode.Node), - remStaticCh: make(chan *enode.Node), - addPeerCh: make(chan *conn), - remPeerCh: make(chan *conn), - updateIPRestrictCh: make(chan []string), + dialConfig: config.withDefaults(), + setupFunc: setupFunc, + dialing: make(map[enode.ID]*dialTask), + static: make(map[enode.ID]*dialTask), + peers: make(map[enode.ID]connFlag), + doneCh: make(chan *dialTask), + nodesIn: make(chan *enode.Node), + addStaticCh: make(chan *enode.Node), + remStaticCh: make(chan *enode.Node), + addPeerCh: make(chan *conn), + remPeerCh: make(chan *conn), } d.lastStatsLog = d.clock.Now() d.ctx, d.cancel = context.WithCancel(context.Background()) @@ -193,13 +191,6 @@ func (d *dialScheduler) stop() { d.wg.Wait() } -func (d *dialScheduler) updateIPRestrict(s []string) { - select { - case d.updateIPRestrictCh <- s: - case <-d.ctx.Done(): - } -} - // addStatic adds a static dial candidate. func (d *dialScheduler) addStatic(n *enode.Node) { select { @@ -271,7 +262,7 @@ loop: d.dialPeers++ } id := c.node.ID() - d.peers[id] = c + d.peers[id] = c.flags // Remove from static pool because the node is now connected. task := d.static[id] if task != nil && task.staticPoolIndex >= 0 { @@ -286,10 +277,6 @@ loop: delete(d.peers, c.node.ID()) d.updateStaticPool(c.node.ID()) - case ips := <-d.updateIPRestrictCh: - d.log.Trace("Update ip restrict", "ips", ips) - d.ipRestrict = ips - case node := <-d.addStaticCh: id := node.ID() _, exists := d.static[id] diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 9e8b3823ac36..60d45139e3f5 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -204,14 +204,6 @@ func (t *UDPv4) Resolve(n *enode.Node) *enode.Node { return n } -func (t *UDPv4) UpdateIPRestrict(ips []string) { - t.iprestrict = ips -} - -func (t *UDPv4) UpdatePrivateNodes(ips []string) { - t.privateNodes = ips -} - func (t *UDPv4) ourEndpoint() v4wire.Endpoint { n := t.Self() a := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} diff --git a/p2p/server.go b/p2p/server.go index 92a3efb0d00b..65cec11facb3 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -199,10 +199,6 @@ type Server struct { quit chan struct{} addtrusted chan *enode.Node removetrusted chan *enode.Node - addiprestrict chan string - removeiprestrict chan string - addprivatenode chan string - removeprivatenode chan string peerOp chan peerOpFunc peerOpDone chan struct{} delpeer chan peerDrop @@ -384,34 +380,6 @@ func (srv *Server) RemoveTrustedPeer(node *enode.Node) { } } -func (srv *Server) AddIPRestrict(ip string) { - select { - case srv.addiprestrict <- ip: - case <-srv.quit: - } -} - -func (srv *Server) RemoveIPRestrict(ip string) { - select { - case srv.removeiprestrict <- ip: - case <-srv.quit: - } -} - -func (srv *Server) AddPrivateNode(node string) { - select { - case srv.addprivatenode <- node: - case <-srv.quit: - } -} - -func (srv *Server) RemovePrivateNode(node string) { - select { - case srv.removeprivatenode <- node: - case <-srv.quit: - } -} - // SubscribeEvents subscribes the given channel to peer events func (srv *Server) SubscribeEvents(ch chan *PeerEvent) event.Subscription { return srv.peerFeed.Subscribe(ch) @@ -509,10 +477,6 @@ func (srv *Server) Start() (err error) { srv.checkpointAddPeer = make(chan *conn) srv.addtrusted = make(chan *enode.Node) srv.removetrusted = make(chan *enode.Node) - srv.addiprestrict = make(chan string) - srv.removeiprestrict = make(chan string) - srv.addprivatenode = make(chan string) - srv.removeprivatenode = make(chan string) srv.peerOp = make(chan peerOpFunc) srv.peerOpDone = make(chan struct{}) @@ -802,76 +766,6 @@ running: p.rw.set(trustedConn, false) } - case ip := <-srv.addiprestrict: - srv.log.Trace("Adding ip restrict", "ip", ip) - - if len(restricts) == 0 { - for _, c := range srv.dialsched.peers { - if c.node.IP().String() != ip { - if p, ok := peers[c.node.ID()]; ok { - delete(peers, c.node.ID()) - srv.dialsched.peerRemoved(c) - if p.Inbound() { - inboundCount-- - } - } - } - } - } - - restricts[ip] = true - ips := []string{} - for ip, _ := range restricts { - ips = append(ips, ip) - } - srv.IPRestrict = ips - srv.dialsched.updateIPRestrict(ips) - srv.ntab.UpdateIPRestrict(ips) - - case ip := <-srv.removeiprestrict: - srv.log.Trace("Removing ip restrict", "ip", ip) - delete(restricts, ip) - ips := []string{} - for ip, _ := range restricts { - ips = append(ips, ip) - } - srv.IPRestrict = ips - srv.dialsched.updateIPRestrict(ips) - srv.ntab.UpdateIPRestrict(ips) - if len(restricts) > 0 { - for _, c := range srv.dialsched.peers { - if c.node.IP().String() == ip { - if p, ok := peers[c.node.ID()]; ok { - delete(peers, c.node.ID()) - srv.dialsched.peerRemoved(c) - if p.Inbound() { - inboundCount-- - } - } - } - } - } - - case p := <-srv.addprivatenode: - srv.log.Trace("Adding private node", "node", p) - privates[p] = true - ips := []string{} - for ip, _ := range privates { - ips = append(ips, ip) - } - srv.PrivateNodes = ips - srv.ntab.UpdatePrivateNodes(ips) - - case p := <-srv.removeprivatenode: - srv.log.Trace("Removing private node", "node", p) - delete(privates, p) - ips := []string{} - for ip, _ := range privates { - ips = append(ips, ip) - } - srv.PrivateNodes = ips - srv.ntab.UpdatePrivateNodes(ips) - case op := <-srv.peerOp: // This channel is used by Peers and PeerCount. op(peers) From 2b6434a5e9c822fc0a727a3e40c228a14db0cc0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Tue, 26 Jul 2022 18:45:52 +0700 Subject: [PATCH 15/18] config private node list by enode --- cmd/utils/flags.go | 2 +- node/api.go | 2 +- p2p/discover/common.go | 12 +++++++++++- p2p/discover/v4_udp.go | 4 ++-- p2p/discover/v5_udp.go | 4 ++-- p2p/enode/node.go | 15 +++++++++++++++ p2p/server.go | 38 ++++++++++++++++---------------------- 7 files changed, 48 insertions(+), 29 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 877369c1f7b2..4d1256af5b89 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1210,7 +1210,7 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { } if privatenodes := ctx.GlobalString(PrivateNodeFlag.Name); privatenodes != "" { - cfg.PrivateNodes = netutil.ParseIPs(privatenodes) + cfg.PrivateNodes = enode.ParseNodes(privatenodes) } if ctx.GlobalBool(DeveloperFlag.Name) || ctx.GlobalBool(CatalystFlag.Name) { diff --git a/node/api.go b/node/api.go index 3f90cb4b6e0b..7e9ed6de9160 100644 --- a/node/api.go +++ b/node/api.go @@ -326,7 +326,7 @@ func (api *publicAdminAPI) Datadir() string { return api.node.DataDir() } -func (api *publicAdminAPI) PrivateNodes() ([]string, error) { +func (api *publicAdminAPI) PrivateNodes() ([]*enode.Node, error) { server := api.node.Server() if server == nil { return nil, ErrNodeStopped diff --git a/p2p/discover/common.go b/p2p/discover/common.go index cf5ca9713ebc..f8e61529881a 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -43,7 +43,7 @@ type Config struct { // These settings are optional: NetRestrict *netutil.Netlist // list of allowed IP networks IPRestrict []string // list of allowed IP addresses - PrivateNodes []string // list of private IPs + PrivateNodes []*enode.Node // list of private enodes Bootnodes []*enode.Node // list of bootstrap nodes Unhandled chan<- ReadPacket // unhandled packets are sent on this channel Log log.Logger // if set, log messages go here @@ -93,3 +93,13 @@ func has(s []string, str string) bool { return false } + +func containsEnode(nodes []*enode.Node, node *enode.Node) bool { + for _, n := range nodes { + if n.IP().Equal(node.IP()) || n.ID() == node.ID() { + return true + } + } + + return false +} diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 60d45139e3f5..e219aebc5d52 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -69,7 +69,7 @@ type UDPv4 struct { log log.Logger netrestrict *netutil.Netlist iprestrict []string - privateNodes []string + privateNodes []*enode.Node priv *ecdsa.PrivateKey localNode *enode.LocalNode db *enode.DB @@ -736,7 +736,7 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno var sent bool for _, n := range closest { // Don't advertise the private nodes - if len(t.privateNodes) > 0 && has(t.privateNodes, n.IP().String()) { + if len(t.privateNodes) > 0 && containsEnode(t.privateNodes, &n.Node) { continue } if netutil.CheckRelayIP(from.IP, n.IP()) == nil { diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index adce0f8c7be4..0e10998b88c8 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -66,7 +66,7 @@ type UDPv5 struct { tab *Table netrestrict *netutil.Netlist iprestrict []string - privateNodes []string + privateNodes []*enode.Node priv *ecdsa.PrivateKey localNode *enode.LocalNode db *enode.DB @@ -821,7 +821,7 @@ func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*en // Apply some pre-checks to avoid sending invalid nodes. for _, n := range bn { // Don't advertise the private nodes - if len(t.privateNodes) > 0 && has(t.privateNodes, n.IP().String()) { + if len(t.privateNodes) > 0 && containsEnode(t.privateNodes, n) { continue } // TODO livenessChecks > 1 diff --git a/p2p/enode/node.go b/p2p/enode/node.go index d747ca331377..78bdf8960794 100644 --- a/p2p/enode/node.go +++ b/p2p/enode/node.go @@ -79,6 +79,21 @@ func Parse(validSchemes enr.IdentityScheme, input string) (*Node, error) { return New(validSchemes, &r) } +func ParseNodes(s string) []*Node { + ws := strings.NewReplacer(" ", "", "\n", "", "\t", "") + urls := strings.Split(ws.Replace(s), ",") + nodes := make([]*Node, 0) + for _, url := range urls { + if url == "" { + continue + } + if node, err := Parse(ValidSchemes, url); err == nil { + nodes = append(nodes, node) + } + } + return nodes +} + // ID returns the node identifier. func (n *Node) ID() ID { return n.id diff --git a/p2p/server.go b/p2p/server.go index 65cec11facb3..57ff3b1a48c5 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -115,9 +115,9 @@ type Config struct { TrustedNodes []*enode.Node // Broadcasting peers' info in the discovery mode can be ignored - // If this option is set to non-nil, the nodes which match one the the - // IPs contained in the list are not broadcasted. - PrivateNodes []string `toml:",omitempty"` + // If this option is set to non-nil, the nodes which match one the + // IPs/enodes contained in the list are not broadcasted. + PrivateNodes []*enode.Node `toml:",omitempty"` // Connectivity can be restricted to certain IP addresses // If this option is set to a non-nil, only nodes which match one of the @@ -600,12 +600,13 @@ func (srv *Server) setupDiscovery() error { sconn = &sharedUDPConn{conn, unhandled} } cfg := discover.Config{ - PrivateKey: srv.PrivateKey, - NetRestrict: srv.NetRestrict, - IPRestrict: srv.IPRestrict, - Bootnodes: srv.BootstrapNodes, - Unhandled: unhandled, - Log: srv.log, + PrivateKey: srv.PrivateKey, + NetRestrict: srv.NetRestrict, + IPRestrict: srv.IPRestrict, + PrivateNodes: srv.PrivateNodes, + Bootnodes: srv.BootstrapNodes, + Unhandled: unhandled, + Log: srv.log, } ntab, err := discover.ListenV4(conn, srv.localnode, cfg) if err != nil { @@ -618,11 +619,12 @@ func (srv *Server) setupDiscovery() error { // Discovery V5 if srv.DiscoveryV5 { cfg := discover.Config{ - PrivateKey: srv.PrivateKey, - NetRestrict: srv.NetRestrict, - IPRestrict: srv.IPRestrict, - Bootnodes: srv.BootstrapNodesV5, - Log: srv.log, + PrivateKey: srv.PrivateKey, + NetRestrict: srv.NetRestrict, + IPRestrict: srv.IPRestrict, + PrivateNodes: srv.PrivateNodes, + Bootnodes: srv.BootstrapNodesV5, + Log: srv.log, } var err error if sconn != nil { @@ -726,20 +728,12 @@ func (srv *Server) run() { peers = make(map[enode.ID]*Peer) inboundCount = 0 trusted = make(map[enode.ID]bool, len(srv.TrustedNodes)) - privates = make(map[string]bool, len(srv.PrivateNodes)) - restricts = make(map[string]bool, len(srv.IPRestrict)) ) // Put trusted nodes into a map to speed up checks. // Trusted peers are loaded on startup or added via AddTrustedPeer RPC. for _, n := range srv.TrustedNodes { trusted[n.ID()] = true } - for _, n := range srv.PrivateNodes { - privates[n] = true - } - for _, ip := range srv.IPRestrict { - restricts[ip] = true - } running: for { From d47eb05d37739f7d6487aee7634d8efaedbee83b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Wed, 27 Jul 2022 15:39:37 +0700 Subject: [PATCH 16/18] show more info for private node list --- node/api.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/node/api.go b/node/api.go index 7e9ed6de9160..5321aecf8285 100644 --- a/node/api.go +++ b/node/api.go @@ -326,12 +326,20 @@ func (api *publicAdminAPI) Datadir() string { return api.node.DataDir() } -func (api *publicAdminAPI) PrivateNodes() ([]*enode.Node, error) { +func (api *publicAdminAPI) PrivateNodes() ([]*p2p.NodeInfo, error) { server := api.node.Server() if server == nil { return nil, ErrNodeStopped } - return server.PrivateNodes, nil + infos := make([]*p2p.NodeInfo, 0, len(server.PrivateNodes)) + for _, node := range server.PrivateNodes { + infos = append(infos, &p2p.NodeInfo{ + ID: node.ID().String(), + Enode: node.URLv4(), + IP: node.IP().String(), + }) + } + return infos, nil } func (api *publicAdminAPI) Iprestrict() ([]string, error) { From 50cc96cf59e35e4782d30f845d62478b8c629ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Tue, 2 Aug 2022 09:08:17 +0700 Subject: [PATCH 17/18] correct private notes flag usage description --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 4d1256af5b89..d1e9222f6fec 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -662,7 +662,7 @@ var ( } PrivateNodeFlag = cli.StringFlag{ Name: "privatenodes", - Usage: "Set list of private nodes IP that not be advertise to public network", + Usage: "Comma separated enode URLs for not be advertise as peers to public network", } DNSDiscoveryFlag = cli.StringFlag{ Name: "discovery.dns", From 61d2a2acd87c0cc9e7780114815955c3a621f5d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Wed, 3 Aug 2022 06:51:21 +0700 Subject: [PATCH 18/18] polish the usage description for private nodes flag --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index d1e9222f6fec..fdded6c6250b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -662,7 +662,7 @@ var ( } PrivateNodeFlag = cli.StringFlag{ Name: "privatenodes", - Usage: "Comma separated enode URLs for not be advertise as peers to public network", + Usage: "Comma separated enode URLs which must not be advertised as peers to public network", } DNSDiscoveryFlag = cli.StringFlag{ Name: "discovery.dns",