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  }