github.com/aergoio/aergo@v1.3.1/polaris/server/listmanager.go (about)

     1  /*
     2   * @file
     3   * @copyright defined in aergo/LICENSE.txt
     4   */
     5  
     6  package server
     7  
     8  import (
     9  	"errors"
    10  	"fmt"
    11  	"github.com/aergoio/aergo-lib/log"
    12  	"github.com/aergoio/aergo/config"
    13  	"github.com/aergoio/aergo/types"
    14  	"github.com/rs/zerolog"
    15  	"io/ioutil"
    16  	"net"
    17  	"os"
    18  	"path/filepath"
    19  	"sync"
    20  	"time"
    21  )
    22  
    23  // variables that are used internally
    24  var (
    25  	NotFoundError = errors.New("ban status not found")
    26  	UndefinedTime = time.Unix(0, 0)
    27  	FarawayFuture = time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC)
    28  )
    29  
    30  const (
    31  	localListFile = "blacklist.json"
    32  )
    33  
    34  type polarisListManager struct {
    35  	logger *log.Logger
    36  	mutex sync.Mutex
    37  
    38  	entries []types.WhiteListEntry
    39  	enabled bool
    40  	rwLock  sync.RWMutex
    41  	authDir string
    42  
    43  	stopScheduler chan interface{}
    44  }
    45  
    46  func NewPolarisListManager(conf *config.PolarisConfig, authDir string, logger *log.Logger) *polarisListManager {
    47  	lm := &polarisListManager{
    48  		logger:  logger,
    49  		enabled: conf.EnableBlacklist,
    50  
    51  		authDir:       authDir,
    52  		stopScheduler: make(chan interface{}),
    53  	}
    54  
    55  	return lm
    56  }
    57  
    58  func (lm *polarisListManager) loadListFile() {
    59  	blFile := filepath.Join(lm.authDir, localListFile)
    60  
    61  	jsonFile, err := os.Open(blFile)
    62  	// if we os.Open returns an error then handle it
    63  	if err != nil {
    64  		lm.logger.Info().Err(err).Str("file", blFile).Msg("Failed to read blacklist file")
    65  		return
    66  	}
    67  	// defer the closing of our jsonFile so that we can parse it later on
    68  	defer jsonFile.Close()
    69  
    70  	// read our opened xmlFile as a byte array.
    71  	byteValue, _ := ioutil.ReadAll(jsonFile)
    72  
    73  	lm.mutex.Lock()
    74  	defer lm.mutex.Unlock()
    75  	entries, err := types.ReadEntries(byteValue)
    76  	if err != nil {
    77  		lm.logger.Info().Err(err).Str("file", blFile).Msg("Failed to parse blacklist file")
    78  		return
    79  	}
    80  	lm.logger.Info().Array("entry",ListEntriesMarshaller{entries, 10}).Msg("Loaded blacklist file")
    81  	lm.entries = entries
    82  }
    83  
    84  func (lm *polarisListManager) saveListFile() {
    85  	blFile := filepath.Join(lm.authDir, localListFile)
    86  	lm.logger.Debug().Str("file", blFile).Msg("Saving local blacklist file")
    87  	jsonFile, err := os.OpenFile(blFile, os.O_WRONLY|os.O_CREATE, 0644)
    88  	if err != nil {
    89  		lm.logger.Info().Err(err).Str("file", blFile).Msg("Failed to open blacklist file for writing")
    90  		return
    91  	}
    92  	defer jsonFile.Close()
    93  	lm.mutex.Lock()
    94  	defer lm.mutex.Unlock()
    95  
    96  	err = types.WriteEntries(lm.entries, jsonFile)
    97  	if err != nil {
    98  		lm.logger.Info().Err(err).Str("file", blFile).Msg("Failed to write blacklist file")
    99  		return
   100  	}
   101  	lm.logger.Info().Array("entry",ListEntriesMarshaller{lm.entries, 10}).Msg("Saved blacklist file")
   102  }
   103  
   104  func (lm *polarisListManager) ListEntries() []types.WhiteListEntry {
   105  	lm.mutex.Lock()
   106  	defer lm.mutex.Unlock()
   107  	newEntry := make([]types.WhiteListEntry,len(lm.entries))
   108  	copy(newEntry, lm.entries)
   109  	return newEntry
   110  }
   111  func (lm *polarisListManager) AddEntry(entry types.WhiteListEntry) {
   112  	lm.mutex.Lock()
   113  	defer lm.mutex.Unlock()
   114  
   115  	newEntry := make([]types.WhiteListEntry,0,len(lm.entries)+1)
   116  	newEntry = append(newEntry, lm.entries...)
   117  	newEntry = append(newEntry, entry)
   118  	lm.entries = newEntry
   119  	lm.logger.Info().Str("entry", entry.String()).Msg("Added blacklist entry")
   120  }
   121  
   122  func (lm *polarisListManager) RemoveEntry(idx int) bool {
   123  	lm.mutex.Lock()
   124  	defer lm.mutex.Unlock()
   125  	if idx < 0 || idx >= len(lm.entries) {
   126  		return false
   127  	}
   128  	toRemove := lm.entries[idx]
   129  	newEntries := make([]types.WhiteListEntry,0,len(lm.entries))
   130  	newEntries = append(newEntries, lm.entries...)
   131  	newEntries = append(newEntries[:idx], newEntries[idx+1:]...)
   132  	lm.entries = newEntries
   133  	lm.logger.Info().Str("entry", toRemove.String()).Msg("Removed blacklist entry")
   134  	return true
   135  }
   136  
   137  
   138  func (lm *polarisListManager) Start() {
   139  	lm.logger.Debug().Msg("starting up list manager")
   140  	if lm.enabled {
   141  		lm.loadListFile()
   142  	}
   143  }
   144  
   145  func (lm *polarisListManager) Stop() {
   146  	lm.logger.Debug().Msg("stopping list manager")
   147  	if lm.enabled {
   148  		lm.saveListFile()
   149  	}
   150  }
   151  
   152  func (lm *polarisListManager) IsBanned(addr string, pid types.PeerID) (bool, time.Time) {
   153  	// polaris is blaklist
   154  	// empty entry means no blacklist
   155  	if !lm.enabled || len(lm.entries) == 0 {
   156  		return false, FarawayFuture
   157  	}
   158  
   159  	// malformed ip address is banned
   160  	ip := net.ParseIP(addr)
   161  	if ip == nil {
   162  		return true, FarawayFuture
   163  	}
   164  
   165  	// finally check peer is in list
   166  	for _, ent := range lm.entries {
   167  		if ent.Contains(ip, pid) {
   168  			return true, FarawayFuture
   169  		}
   170  	}
   171  	return false, FarawayFuture
   172  }
   173  
   174  func (lm *polarisListManager) RefineList() {
   175  	// no refine is needed
   176  }
   177  
   178  func (lm *polarisListManager) Summary() map[string]interface{} {
   179  	// There can be a little error
   180  	sum := make(map[string]interface{})
   181  	entries := make([]string, 0, len(lm.entries))
   182  	for _, e := range lm.entries {
   183  		entries = append(entries, e.String())
   184  	}
   185  	sum["blacklist"] = entries
   186  	sum["blacklist_on"] = lm.enabled
   187  
   188  	return sum
   189  }
   190  
   191  type ListEntriesMarshaller struct {
   192  	arr []types.WhiteListEntry
   193  	limit int
   194  }
   195  
   196  func (m ListEntriesMarshaller) MarshalZerologArray(a *zerolog.Array) {
   197  	size := len(m.arr)
   198  	if size > m.limit {
   199  		for i := 0; i < m.limit-1; i++ {
   200  			a.Str(m.arr[i].String())
   201  		}
   202  		a.Str(fmt.Sprintf("(and %d more)", size-m.limit+1))
   203  	} else {
   204  		for _, element := range m.arr {
   205  			a.Str(element.String())
   206  		}
   207  	}
   208  }