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 }