diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 15dfd228bc..a2e48c7465 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -145,6 +145,7 @@ var ( // utils.MinerNewPayloadTimeout, utils.NATFlag, utils.NoDiscoverFlag, + utils.PeerFilterPatternsFlag, utils.DiscoveryV4Flag, utils.DiscoveryV5Flag, utils.InstanceFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index a5962b8a82..7c30a6b247 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -882,6 +882,11 @@ var ( Usage: "Disables the peer discovery mechanism (manual peer addition)", Category: flags.NetworkingCategory, } + PeerFilterPatternsFlag = &cli.StringSliceFlag{ + Name: "peerfilter", + Usage: "Disallow peers connection if peer name matches the given regular expressions", + Category: flags.NetworkingCategory, + } DiscoveryV4Flag = &cli.BoolFlag{ Name: "discovery.v4", Aliases: []string{"discv4"}, @@ -1548,6 +1553,9 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { if ctx.IsSet(NoDiscoverFlag.Name) { cfg.NoDiscovery = true } + if ctx.IsSet(PeerFilterPatternsFlag.Name) { + cfg.PeerFilterPatterns = ctx.StringSlice(PeerFilterPatternsFlag.Name) + } CheckExclusive(ctx, DiscoveryV4Flag, NoDiscoverFlag) CheckExclusive(ctx, DiscoveryV5Flag, NoDiscoverFlag) diff --git a/p2p/server.go b/p2p/server.go index aef27dcbfc..a334166737 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" "net" + "regexp" "sync" "sync/atomic" "time" @@ -180,6 +181,8 @@ type Config struct { // Logger is a custom logger to use with the p2p.Server. Logger log.Logger `toml:",omitempty"` + PeerFilterPatterns []string + clock mclock.Clock } @@ -210,7 +213,8 @@ type Server struct { discmix *enode.FairMix dialsched *dialScheduler - forkFilter forkid.Filter + forkFilter forkid.Filter + peerNameFilter []*regexp.Regexp // This is read by the NAT port mapping loop. portMappingRegister chan *portMapping @@ -540,6 +544,15 @@ func (srv *Server) Start() (err error) { } srv.setupDialScheduler() + if srv.PeerFilterPatterns != nil { + pat, err := compilePeerFilterPatterns(srv.PeerFilterPatterns) + if err != nil { + log.Error("Failed to compile peer filter patterns", "err", err) + pat = nil + } + srv.peerNameFilter = pat + } + srv.loopWG.Add(1) go srv.run() return nil @@ -916,6 +929,14 @@ func (srv *Server) addPeerChecks(peers map[enode.ID]*Peer, inboundCount int, c * return errors.New("explicitly disconnected peer previously") } + if srv.peerNameFilter != nil { + for _, re := range srv.peerNameFilter { + if re.MatchString(c.name) { + return errors.New("peer name matches filter") + } + } + } + // Repeat the post-handshake checks because the // peer set might have changed since those checks were performed. return srv.postHandshakeChecks(peers, inboundCount, c) @@ -1226,3 +1247,15 @@ func (srv *Server) PeersInfo() []*PeerInfo { } return infos } + +func compilePeerFilterPatterns(pat []string) ([]*regexp.Regexp, error) { + var filters []*regexp.Regexp + for _, filter := range pat { + r, err := regexp.Compile(filter) + if err != nil { + return nil, err + } + filters = append(filters, r) + } + return filters, nil +}