diff --git a/server.go b/server.go index 42f34da5..ab2c31fe 100644 --- a/server.go +++ b/server.go @@ -246,6 +246,14 @@ type server struct { // messages for each filter type. cfCheckptCaches map[wire.FilterType][]cfHeaderKV cfCheckptCachesMtx sync.RWMutex + + // agentBlacklist is a list of blacklisted substrings by which to filter + // user agents. + agentBlacklist []string + + // agentWhitelist is a list of whitelisted user agent substrings, no + // whitelisting will be applied if the list is empty or nil. + agentWhitelist []string } // serverPeer extends the peer to maintain state shared by the server and @@ -1586,6 +1594,12 @@ func (s *server) handleAddPeerMsg(state *peerState, sp *serverPeer) bool { return false } + // Disconnect peers with unwanted user agents. + if sp.HasUndesiredUserAgent(s.agentBlacklist, s.agentWhitelist) { + sp.Disconnect() + return false + } + // Ignore new peers if we're shutting down. if atomic.LoadInt32(&s.shutdown) != 0 { srvrLog.Infof("New peer %s ignored - server is shutting down", sp) @@ -3133,3 +3147,47 @@ func mergeCheckpoints(defaultCheckpoints, additional []chaincfg.Checkpoint) []ch sort.Sort(checkpointSorter(checkpoints)) return checkpoints } + +// HasUndesiredUserAgent determines whether the server should continue to pursue +// a connection with this peer based on its advertised user agent. It performs +// the following steps: +// 1) Reject the peer if it contains a blacklisted agent. +// 2) If no whitelist is provided, accept all user agents. +// 3) Accept the peer if it contains a whitelisted agent. +// 4) Reject all other peers. +func (sp *serverPeer) HasUndesiredUserAgent(blacklistedAgents, + whitelistedAgents []string) bool { + + agent := sp.UserAgent() + + // First, if peer's user agent contains any blacklisted substring, we + // will ignore the connection request. + for _, blacklistedAgent := range blacklistedAgents { + if strings.Contains(agent, blacklistedAgent) { + srvrLog.Debugf("Ignoring peer %s, user agent "+ + "contains blacklisted user agent: %s", sp, + agent) + return true + } + } + + // If no whitelist is provided, we will accept all user agents. + if len(whitelistedAgents) == 0 { + return false + } + + // Peer's user agent passed blacklist. Now check to see if it contains + // one of our whitelisted user agents, if so accept. + for _, whitelistedAgent := range whitelistedAgents { + if strings.Contains(agent, whitelistedAgent) { + return false + } + } + + // Otherwise, the peer's user agent was not included in our whitelist. + // Ignore just in case it could stall the initial block download. + srvrLog.Debugf("Ignoring peer %s, user agent: %s not found in "+ + "whitelist", sp, agent) + + return true +}