github.com/ethersphere/bee/v2@v2.2.0/pkg/p2p/libp2p/internal/blocklist/blocklist.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package blocklist 6 7 import ( 8 "errors" 9 "strings" 10 "time" 11 12 "github.com/ethersphere/bee/v2/pkg/p2p" 13 "github.com/ethersphere/bee/v2/pkg/storage" 14 "github.com/ethersphere/bee/v2/pkg/swarm" 15 ) 16 17 var keyPrefix = "blocklist-" 18 19 type currentTimeFn = func() time.Time 20 21 type Blocklist struct { 22 store storage.StateStorer 23 currentTimeFn currentTimeFn 24 } 25 26 func NewBlocklist(store storage.StateStorer) *Blocklist { 27 return &Blocklist{ 28 store: store, 29 currentTimeFn: time.Now, 30 } 31 } 32 33 type entry struct { 34 Timestamp time.Time `json:"timestamp"` 35 Duration string `json:"duration"` // Duration is string because the time.Duration does not implement MarshalJSON/UnmarshalJSON methods. 36 Reason string `json:"reason"` 37 Full bool `json:"full"` 38 } 39 40 func (b *Blocklist) Exists(overlay swarm.Address) (bool, error) { 41 key := generateKey(overlay) 42 e, duration, err := b.get(key) 43 if err != nil { 44 if errors.Is(err, storage.ErrNotFound) { 45 return false, nil 46 } 47 48 return false, err 49 } 50 51 if b.currentTimeFn().Sub(e.Timestamp) > duration && duration != 0 { 52 _ = b.store.Delete(key) 53 return false, nil 54 } 55 56 return true, nil 57 } 58 59 func (b *Blocklist) Add(overlay swarm.Address, duration time.Duration, reason string, full bool) (err error) { 60 key := generateKey(overlay) 61 _, d, err := b.get(key) 62 if err != nil { 63 if !errors.Is(err, storage.ErrNotFound) { 64 return err 65 } 66 } 67 68 // if peer is already blacklisted, blacklist it for the maximum amount of time 69 if duration < d && duration != 0 || d == 0 { 70 duration = d 71 } 72 73 return b.store.Put(key, &entry{ 74 Timestamp: b.currentTimeFn(), 75 Duration: duration.String(), 76 Reason: reason, 77 Full: full, 78 }) 79 } 80 81 // Peers returns all currently blocklisted peers. 82 func (b *Blocklist) Peers() ([]p2p.BlockListedPeer, error) { 83 var peers []p2p.BlockListedPeer 84 if err := b.store.Iterate(keyPrefix, func(k, v []byte) (bool, error) { 85 if !strings.HasPrefix(string(k), keyPrefix) { 86 return true, nil 87 } 88 addr, err := unmarshalKey(string(k)) 89 if err != nil { 90 return true, err 91 } 92 93 entry, d, err := b.get(string(k)) 94 if err != nil { 95 return true, err 96 } 97 98 if b.currentTimeFn().Sub(entry.Timestamp) > d && d != 0 { 99 // skip to the next item 100 return false, nil 101 } 102 103 p := p2p.BlockListedPeer{ 104 Peer: p2p.Peer{ 105 Address: addr, 106 FullNode: entry.Full, 107 }, 108 Duration: d, 109 Reason: entry.Reason, 110 } 111 peers = append(peers, p) 112 return false, nil 113 }); err != nil { 114 return nil, err 115 } 116 117 return peers, nil 118 } 119 120 func (b *Blocklist) get(key string) (entry, time.Duration, error) { 121 var e entry 122 err := b.store.Get(key, &e) 123 if err != nil { 124 return e, -1, err 125 } 126 127 dur, err := time.ParseDuration(e.Duration) 128 if err != nil { 129 return e, -1, err 130 } 131 132 return e, dur, nil 133 } 134 135 func generateKey(overlay swarm.Address) string { 136 return keyPrefix + overlay.String() 137 } 138 139 func unmarshalKey(s string) (swarm.Address, error) { 140 addr := s[len(keyPrefix):] // trim prefix 141 return swarm.ParseHexAddress(addr) 142 }