github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/p2p/bans.go (about) 1 // Copyright 2017-2018 DERO Project. All rights reserved. 2 // Use of this source code in any form is governed by RESEARCH license. 3 // license can be found in the LICENSE file. 4 // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 5 // 6 // 7 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 9 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 10 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 11 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 12 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 13 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 14 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 15 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 17 package p2p 18 19 /* this file implements the peer manager, keeping a list of peers which can be tried for connection etc 20 * 21 */ 22 import "os" 23 import "fmt" 24 import "net" 25 import "sync" 26 import "time" 27 28 //import "sort" 29 import "path/filepath" 30 import "encoding/json" 31 32 //import "encoding/binary" 33 //import "container/list" 34 35 //import log "github.com/sirupsen/logrus" 36 37 import "github.com/deroproject/derosuite/globals" 38 39 //import "github.com/deroproject/derosuite/crypto" 40 41 // This structure is used to do book keeping for the peer list and keeps other DATA related to peer 42 // all peers are servers, means they have exposed a port for connections 43 // all peers are identified by their endpoint tcp address 44 // all clients are identified by ther peer id ( however ip-address is used to control amount ) 45 // the following daemon commands interact with the list 46 // bans := print current ban list 47 // ban address time // ban this address for specific time, if time not provided , default ban for 10 minutes 48 // unban address 49 // enableban address // by default all addresses are bannable 50 // disableban address // this address will never be banned 51 52 var ban_map = map[string]uint64{} // keeps ban maps 53 var ban_mutex sync.Mutex 54 55 // loads peers list from disk 56 func load_ban_list() { 57 go ban_clean_up_goroutine() // start routine to clean up ban list 58 defer ban_clean_up() // cleanup list after loading it 59 ban_mutex.Lock() 60 defer ban_mutex.Unlock() 61 62 ban_file := filepath.Join(globals.GetDataDirectory(), "ban_list.json") 63 file, err := os.Open(ban_file) 64 if err != nil { 65 logger.Warnf("Error opening ban data file %s err %s", ban_file, err) 66 } else { 67 defer file.Close() 68 decoder := json.NewDecoder(file) 69 err = decoder.Decode(&ban_map) 70 if err != nil { 71 logger.Warnf("Error unmarshalling ban data err %s", err) 72 } else { // successfully unmarshalled data 73 logger.Debugf("Successfully loaded %d bans from file", (len(ban_map))) 74 } 75 } 76 } 77 78 //save ban list to disk 79 func save_ban_list() { 80 81 ban_clean_up() // cleanup before saving 82 ban_mutex.Lock() 83 defer ban_mutex.Unlock() 84 85 ban_file := filepath.Join(globals.GetDataDirectory(), "ban_list.json") 86 file, err := os.Create(ban_file) 87 if err != nil { 88 logger.Warnf("Error creating ban data file %s err %s", ban_file, err) 89 } else { 90 defer file.Close() 91 encoder := json.NewEncoder(file) 92 encoder.SetIndent("", "\t") 93 err = encoder.Encode(&ban_map) 94 if err != nil { 95 logger.Warnf("Error marshalling ban data err %s", err) 96 } else { // successfully unmarshalled data 97 logger.Debugf("Successfully saved %d bans to file", (len(ban_map))) 98 } 99 } 100 } 101 102 // clean up ban list every 20 seconds 103 func ban_clean_up_goroutine() { 104 for { 105 select { 106 case <-Exit_Event: 107 return 108 case <-time.After(20 * time.Second): 109 } 110 ban_clean_up() 111 } 112 113 } 114 115 /* used for manual simulation once to track a hard to find bug 116 func init() { 117 load_ban_list() 118 Ban_Address("188.191.128.64/24",600) 119 120 IsAddressInBanList("35.185.240.198") 121 } 122 */ 123 124 // clean up by discarding entries which are in the past 125 func ban_clean_up() { 126 ban_mutex.Lock() 127 defer ban_mutex.Unlock() 128 129 current_time := uint64(time.Now().UTC().Unix()) 130 for k, v := range ban_map { 131 if v < current_time { 132 delete(ban_map, k) 133 } 134 } 135 } 136 137 // convert address to subnet form 138 // address is an IP address or ipnet in string form 139 func ParseAddress(address string) (ipnet *net.IPNet, result string, err error) { 140 var ip net.IP 141 ip, ipnet, err = net.ParseCIDR(address) 142 if err != nil { // other check whether the the IP is an IP 143 ip = net.ParseIP(address) 144 if ip == nil { 145 err = fmt.Errorf("IP address could not be parsed") 146 return 147 } else { 148 err = nil 149 result = ip.String() 150 } 151 152 } else { 153 result = ipnet.String() 154 } 155 return 156 } 157 158 // check whether an IP is in the map already 159 // we should loop and search in subnets also 160 // TODO make it fast, however we are not expecting millions of bans, so this may be okay for time being 161 func IsAddressInBanList(address string) bool { 162 ban_mutex.Lock() 163 defer ban_mutex.Unlock() 164 165 // any i which cannot be banned should never be banned 166 // this list contains any seed nodes/exclusive nodes/proirity nodes 167 // these are never banned 168 for i := range nonbanlist { 169 if address == nonbanlist[i] { 170 return true 171 } 172 } 173 174 // if it's a subnet or direct ip, do instant check 175 if _, ok := ban_map[address]; ok { 176 return true 177 } 178 179 ip := net.ParseIP(address) // user provided a valid ip parse and check subnet 180 if ip != nil { 181 182 // parse and check the subnets 183 for k, _ := range ban_map { 184 ipnet, _, err := ParseAddress(k) 185 186 // fmt.Printf("parsing address %s err %s checking ip %s",k,err,address) 187 188 // fmt.Printf("\nipnet %+v", ipnet) 189 if ip.String() == k || (err == nil && ipnet != nil && ipnet.Contains(ip)) { 190 return true 191 } 192 193 } 194 } 195 return false 196 } 197 198 // ban a peer for specific time 199 // manual bans are always placed 200 // address can be an address or a subnet 201 202 func Ban_Address(address string, ban_seconds uint64) (err error) { 203 ban_mutex.Lock() 204 defer ban_mutex.Unlock() 205 206 // make sure we are not banning seed nodes/exclusive node/priority nodes on command line 207 _, address, err = ParseAddress(address) 208 if err != nil { 209 return 210 } 211 212 //logger.Warnf("%s banned for %d secs", address, ban_seconds) 213 ban_map[address] = uint64(time.Now().UTC().Unix()) + ban_seconds 214 return 215 } 216 217 /* 218 /// ban a peer only if it can be banned 219 func Peer_Ban_Internal(address string, ban_seconds uint64) (err error){ 220 p := GetPeerInList(address) 221 if p == nil { 222 return fmt.Errorf("Peer \"%s\" not found in list") 223 } 224 p.Lock() 225 defer p.Unlock() 226 if p.NeverBlacklist == false { 227 p.BlacklistBefore = uint64(time.Now().Unix()) + ban_seconds 228 } 229 } 230 */ 231 232 // unban a peer for specific time 233 func UnBan_Address(address string) (err error) { 234 if !IsAddressInBanList(address) { 235 return fmt.Errorf("Address \"%s\" not found in ban list", address) 236 } 237 ban_mutex.Lock() 238 defer ban_mutex.Unlock() 239 logger.Infof("%s unbanned", address) 240 delete(ban_map, address) 241 return 242 } 243 244 /* 245 func Peer_DisableBan(address string) (err error){ 246 p := GetPeerInList(address) 247 if p == nil { 248 return fmt.Errorf("Peer \"%s\" not found in list") 249 } 250 p.Lock() 251 defer p.Unlock() 252 p.NeverBlacklist = true 253 } 254 255 func Peer_EnableBan(address string) (err error){ 256 p := GetPeerInList(address) 257 if p == nil { 258 return fmt.Errorf("Peer \"%s\" not found in list") 259 } 260 p.Lock() 261 defer p.Unlock() 262 p.NeverBlacklist = false 263 } 264 */ 265 266 // prints all the connection info to screen 267 func BanList_Print() { 268 ban_clean_up() // clean up before printing 269 ban_mutex.Lock() 270 defer ban_mutex.Unlock() 271 fmt.Printf("Ban List contains %d \n", len(ban_map)) 272 fmt.Printf("%-22s %-6s\n", "Addr", "Seconds to unban") 273 274 for k, v := range ban_map { 275 fmt.Printf("%-22s %6d\n", k, v-uint64(time.Now().UTC().Unix())) 276 } 277 278 } 279 280 // this function return peer count which have successful handshake 281 func Ban_Count() (Count uint64) { 282 ban_mutex.Lock() 283 defer ban_mutex.Unlock() 284 return uint64(len(ban_map)) 285 }