mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
cmd, node, p2p: implement whitelist and blacklist for peers (#1331)
This commit is contained in:
parent
0ceeb24fb3
commit
4ec6e8cd58
5 changed files with 133 additions and 5 deletions
|
|
@ -61,6 +61,8 @@ var (
|
|||
utils.IdentityFlag,
|
||||
utils.UnlockedAccountFlag,
|
||||
utils.PasswordFileFlag,
|
||||
utils.PeersWhitelistFlag,
|
||||
utils.PeersBlacklistFlag,
|
||||
utils.BootnodesFlag,
|
||||
utils.BootnodesV4Flag,
|
||||
utils.BootnodesV5Flag,
|
||||
|
|
|
|||
|
|
@ -639,6 +639,18 @@ var (
|
|||
Value: 30303,
|
||||
Category: flags.NetworkingCategory,
|
||||
}
|
||||
PeersWhitelistFlag = &cli.StringFlag{
|
||||
Name: "peers-whitelist",
|
||||
Usage: "Comma separated NodeID or enode URLs for peer whitelist (only connect to them)",
|
||||
Value: "",
|
||||
Category: flags.NetworkingCategory,
|
||||
}
|
||||
PeersBlacklistFlag = &cli.StringFlag{
|
||||
Name: "peers-blacklist",
|
||||
Usage: "Comma separated NodeID or enode URLs for peer blacklist (will not connect to them)",
|
||||
Value: "",
|
||||
Category: flags.NetworkingCategory,
|
||||
}
|
||||
BootnodesFlag = &cli.StringFlag{
|
||||
Name: "bootnodes",
|
||||
Usage: "Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)",
|
||||
|
|
@ -954,6 +966,73 @@ func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
|
|||
}
|
||||
}
|
||||
|
||||
func setWhiteBlackListPeers(ctx *cli.Context, cfg *p2p.Config) {
|
||||
CheckExclusive(ctx, PeersWhitelistFlag, PeersBlacklistFlag)
|
||||
|
||||
// setup whitelist for peers
|
||||
if ctx.IsSet(PeersWhitelistFlag.Name) {
|
||||
urls := SplitAndTrim(ctx.String(PeersWhitelistFlag.Name))
|
||||
cfg.WhitePeers = make(map[discover.NodeID]struct{}, len(urls))
|
||||
for _, url := range urls {
|
||||
if url != "" {
|
||||
node1, err1 := discover.HexID(url)
|
||||
if err1 == nil {
|
||||
cfg.WhitePeers[node1] = struct{}{}
|
||||
log.Info("Add peer to whitelist", "id", node1.String())
|
||||
continue
|
||||
}
|
||||
node2, err2 := discover.ParseNode(url)
|
||||
if err2 == nil {
|
||||
cfg.WhitePeers[node2.ID] = struct{}{}
|
||||
log.Info("Add peer to whitelist", "enode", url, "id", node2.ID.String())
|
||||
continue
|
||||
}
|
||||
log.Crit("Invalid peer id for whitelist", "url", url, "err1", err1, "err2", err2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup blacklist for peers
|
||||
if ctx.IsSet(PeersBlacklistFlag.Name) {
|
||||
urls := SplitAndTrim(ctx.String(PeersBlacklistFlag.Name))
|
||||
cfg.BlackPeers = make(map[discover.NodeID]struct{}, len(urls))
|
||||
for _, url := range urls {
|
||||
if url != "" {
|
||||
node1, err1 := discover.HexID(url)
|
||||
if err1 == nil {
|
||||
cfg.BlackPeers[node1] = struct{}{}
|
||||
log.Info("Add peer to blacklsit", "id", node1.String())
|
||||
continue
|
||||
}
|
||||
node2, err2 := discover.ParseNode(url)
|
||||
if err2 == nil {
|
||||
cfg.BlackPeers[node2.ID] = struct{}{}
|
||||
log.Info("Add peer to blacklsit", "enode", url, "id", node2.ID.String())
|
||||
continue
|
||||
}
|
||||
log.Crit("Invalid peer id for blacklist", "url", url, "err1", err1, "err2", err2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// removeBlackPeers removes bootstrap nodes which is in peers blacklist
|
||||
func removeBlackPeers(cfg *p2p.Config) {
|
||||
if len(cfg.BlackPeers) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
filteredNodes := make([]*discover.Node, 0, len(cfg.BootstrapNodes))
|
||||
for _, node := range cfg.BootstrapNodes {
|
||||
if _, ok := cfg.BlackPeers[node.ID]; ok {
|
||||
log.Info("Remove black peer", "enode", node.String(), "id", node.ID)
|
||||
continue
|
||||
}
|
||||
filteredNodes = append(filteredNodes, node)
|
||||
}
|
||||
cfg.BootstrapNodes = filteredNodes
|
||||
}
|
||||
|
||||
// setBootstrapNodes creates a list of bootstrap nodes from the command line
|
||||
// flags, reverting to pre-configured ones if none have been specified.
|
||||
// Priority order for bootnodes configuration:
|
||||
|
|
@ -1249,6 +1328,8 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
|
|||
setNAT(ctx, cfg)
|
||||
setListenAddress(ctx, cfg)
|
||||
setBootstrapNodes(ctx, cfg)
|
||||
setWhiteBlackListPeers(ctx, cfg)
|
||||
removeBlackPeers(cfg)
|
||||
// setBootstrapNodesV5(ctx, cfg)
|
||||
|
||||
if ctx.IsSet(MaxPeersFlag.Name) {
|
||||
|
|
|
|||
24
node/api.go
24
node/api.go
|
|
@ -65,6 +65,18 @@ func (api *adminAPI) AddPeer(url string) (bool, error) {
|
|||
if err != nil {
|
||||
return false, fmt.Errorf("invalid enode: %v", err)
|
||||
}
|
||||
// only accept the node which is in peer whitelist if the list is not empty
|
||||
if len(server.WhitePeers) > 0 {
|
||||
if _, ok := server.WhitePeers[node.ID]; !ok {
|
||||
return false, fmt.Errorf("peer is not in whitelist: %v, ID: %s", url, node.ID)
|
||||
}
|
||||
}
|
||||
// reject the node which is in peer blacklist
|
||||
if len(server.BlackPeers) > 0 {
|
||||
if _, ok := server.BlackPeers[node.ID]; ok {
|
||||
return false, fmt.Errorf("peer is in blacklist: %v, ID: %s", url, node.ID)
|
||||
}
|
||||
}
|
||||
server.AddPeer(node)
|
||||
return true, nil
|
||||
}
|
||||
|
|
@ -96,6 +108,18 @@ func (api *adminAPI) AddTrustedPeer(url string) (bool, error) {
|
|||
if err != nil {
|
||||
return false, fmt.Errorf("invalid enode: %v", err)
|
||||
}
|
||||
// only accept the node which is in peer whitelist if the list is not empty
|
||||
if len(server.WhitePeers) > 0 {
|
||||
if _, ok := server.WhitePeers[node.ID]; !ok {
|
||||
return false, fmt.Errorf("trusted peer is not in whitelist: %v, ID: %s", url, node.ID)
|
||||
}
|
||||
}
|
||||
// reject the node which is in peer blacklist
|
||||
if len(server.BlackPeers) > 0 {
|
||||
if _, ok := server.BlackPeers[node.ID]; ok {
|
||||
return false, fmt.Errorf("trusted peer is in blacklist: %v, ID: %s", url, node.ID)
|
||||
}
|
||||
}
|
||||
server.AddTrustedPeer(node)
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,9 @@ const (
|
|||
DiscSelf
|
||||
DiscReadTimeout
|
||||
DiscPairPeerStop
|
||||
DiscSubprotocolError = 0x10
|
||||
DiscNonWhitelistedPeer
|
||||
DiscBlacklistedPeer
|
||||
DiscSubprotocolError = DiscReason(0x10)
|
||||
)
|
||||
|
||||
var discReasonToString = [...]string{
|
||||
|
|
@ -89,11 +91,13 @@ var discReasonToString = [...]string{
|
|||
DiscSelf: "connected to self",
|
||||
DiscReadTimeout: "read timeout",
|
||||
DiscPairPeerStop: "pair peer connection stop",
|
||||
DiscNonWhitelistedPeer: "disconnect non-whitelisted peer",
|
||||
DiscBlacklistedPeer: "disconnect blacklisted peer",
|
||||
DiscSubprotocolError: "subprotocol error",
|
||||
}
|
||||
|
||||
func (d DiscReason) String() string {
|
||||
if len(discReasonToString) <= int(d) || int(d) < 0 {
|
||||
if len(discReasonToString) <= int(d) || int(d) < 0 || discReasonToString[int(d)] == "" {
|
||||
return fmt.Sprintf("unknown disconnect reason %d", d)
|
||||
}
|
||||
return discReasonToString[int(d)]
|
||||
|
|
@ -107,7 +111,7 @@ func discReasonForError(err error) DiscReason {
|
|||
if reason, ok := err.(DiscReason); ok {
|
||||
return reason
|
||||
}
|
||||
if err == errProtocolReturned {
|
||||
if errors.Is(err, errProtocolReturned) {
|
||||
return DiscQuitting
|
||||
}
|
||||
peerError, ok := err.(*peerError)
|
||||
|
|
|
|||
|
|
@ -87,6 +87,11 @@ type Config struct {
|
|||
// Name sets the node name of this server.
|
||||
Name string `toml:"-"`
|
||||
|
||||
// Whitelist for peers
|
||||
WhitePeers map[discover.NodeID]struct{}
|
||||
// Blacklist for peers.
|
||||
BlackPeers map[discover.NodeID]struct{}
|
||||
|
||||
// BootstrapNodes are used to establish connectivity
|
||||
// with the rest of the network.
|
||||
BootstrapNodes []*discover.Node
|
||||
|
|
@ -892,7 +897,19 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) e
|
|||
srv.log.Trace("Failed RLPx handshake", "addr", c.fd.RemoteAddr(), "conn", c.flags, "err", err)
|
||||
return err
|
||||
}
|
||||
clog := srv.log.New("id", c.id, "addr", c.fd.RemoteAddr(), "conn", c.flags)
|
||||
clog := srv.log.New("id", c.id.String(), "addr", c.fd.RemoteAddr(), "conn", c.flags)
|
||||
if len(srv.WhitePeers) > 0 {
|
||||
if _, ok := srv.WhitePeers[c.id]; !ok {
|
||||
clog.Debug("Reject non-whitelisted peer")
|
||||
return DiscNonWhitelistedPeer
|
||||
}
|
||||
}
|
||||
if len(srv.BlackPeers) > 0 {
|
||||
if _, ok := srv.BlackPeers[c.id]; ok {
|
||||
clog.Debug("Reject blacklisted peer")
|
||||
return DiscBlacklistedPeer
|
||||
}
|
||||
}
|
||||
// For dialed connections, check that the remote public key matches.
|
||||
if dialDest != nil && c.id != dialDest.ID {
|
||||
clog.Trace("Dialed identity mismatch", "want", c, dialDest.ID)
|
||||
|
|
@ -921,7 +938,7 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) e
|
|||
}
|
||||
// If the checks completed successfully, runPeer has now been
|
||||
// launched by run.
|
||||
clog.Trace("connection set up", "inbound", dialDest == nil)
|
||||
clog.Debug("Setup connection")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue