|  | @@ -17,10 +17,10 @@ const (
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  var (
 | 
	
		
			
				|  |  | -	// Log for sending client events from the server to the dashboard.
 | 
	
		
			
				|  |  |  	tickInterval          = time.Second * 5
 | 
	
		
			
				|  |  |  	maxWindow             = time.Hour * 24
 | 
	
		
			
				|  |  |  	rankingUpdateInterval = time.Hour * 6
 | 
	
		
			
				|  |  | +	uniqueHeloRatioMax    = 0.8
 | 
	
		
			
				|  |  |  	maxTicks              = int(maxWindow / tickInterval)
 | 
	
		
			
				|  |  |  	nRankingBuffers       = int(maxWindow / rankingUpdateInterval)
 | 
	
		
			
				|  |  |  	LogHook               = logHook(1)
 | 
	
	
		
			
				|  | @@ -40,10 +40,12 @@ type dataStore struct {
 | 
	
		
			
				|  |  |  	// List of samples of number of connected clients
 | 
	
		
			
				|  |  |  	nClientTicks []point
 | 
	
		
			
				|  |  |  	// Up-to-date number of clients
 | 
	
		
			
				|  |  | -	nClients  uint64
 | 
	
		
			
				|  |  | -	topDomain bufferedRanking
 | 
	
		
			
				|  |  | -	topHelo   bufferedRanking
 | 
	
		
			
				|  |  | -	topIP     bufferedRanking
 | 
	
		
			
				|  |  | +	nClients uint64
 | 
	
		
			
				|  |  | +	// Total number of clients in the current aggregation buffer
 | 
	
		
			
				|  |  | +	nClientsInBuffer uint64
 | 
	
		
			
				|  |  | +	topDomain        bufferedRanking
 | 
	
		
			
				|  |  | +	topHelo          bufferedRanking
 | 
	
		
			
				|  |  | +	topIP            bufferedRanking
 | 
	
		
			
				|  |  |  	// For notifying the store about new connections
 | 
	
		
			
				|  |  |  	newConns chan conn
 | 
	
		
			
				|  |  |  	subs     map[string]chan<- *message
 | 
	
	
		
			
				|  | @@ -86,7 +88,16 @@ func (ds *dataStore) rankingManager() {
 | 
	
		
			
				|  |  |  	for {
 | 
	
		
			
				|  |  |  		select {
 | 
	
		
			
				|  |  |  		case c := <-ds.newConns:
 | 
	
		
			
				|  |  | +			nHelos := len(ds.topHelo)
 | 
	
		
			
				|  |  | +			if nHelos > 5 &&
 | 
	
		
			
				|  |  | +				float64(nHelos)/float64(ds.nClientsInBuffer) > uniqueHeloRatioMax {
 | 
	
		
			
				|  |  | +				// If too many unique HELO messages are detected as a ratio to the total
 | 
	
		
			
				|  |  | +				// number of clients, quit collecting data until we roll over into the next
 | 
	
		
			
				|  |  | +				// aggregation buffer.
 | 
	
		
			
				|  |  | +				continue
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  |  			ds.lock.Lock()
 | 
	
		
			
				|  |  | +			ds.nClientsInBuffer++
 | 
	
		
			
				|  |  |  			ds.topDomain[0][c.domain]++
 | 
	
		
			
				|  |  |  			ds.topHelo[0][c.helo]++
 | 
	
		
			
				|  |  |  			ds.topIP[0][c.ip]++
 | 
	
	
		
			
				|  | @@ -95,6 +106,7 @@ func (ds *dataStore) rankingManager() {
 | 
	
		
			
				|  |  |  		case <-ticker.C:
 | 
	
		
			
				|  |  |  			ds.lock.Lock()
 | 
	
		
			
				|  |  |  			// Add empty map at index 0 and shift other maps one down
 | 
	
		
			
				|  |  | +			ds.nClientsInBuffer = 0
 | 
	
		
			
				|  |  |  			ds.topDomain = append(
 | 
	
		
			
				|  |  |  				[]map[string]int{map[string]int{}},
 | 
	
		
			
				|  |  |  				ds.topDomain[:len(ds.topDomain)-1]...)
 |