mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-11-11 02:35:18 +00:00
126 lines
3.0 KiB
Go
126 lines
3.0 KiB
Go
package relay
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
"time"
|
|
|
|
asnutil "github.com/libp2p/go-libp2p-asn-util"
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
|
|
|
ma "github.com/multiformats/go-multiaddr"
|
|
manet "github.com/multiformats/go-multiaddr/net"
|
|
)
|
|
|
|
var validity = 30 * time.Minute
|
|
|
|
var (
|
|
errTooManyReservations = errors.New("too many reservations")
|
|
errTooManyReservationsForPeer = errors.New("too many reservations for peer")
|
|
errTooManyReservationsForIP = errors.New("too many peers for IP address")
|
|
errTooManyReservationsForASN = errors.New("too many peers for ASN")
|
|
)
|
|
|
|
// constraints implements various reservation constraints
|
|
type constraints struct {
|
|
rc *Resources
|
|
|
|
mutex sync.Mutex
|
|
total []time.Time
|
|
peers map[peer.ID][]time.Time
|
|
ips map[string][]time.Time
|
|
asns map[string][]time.Time
|
|
}
|
|
|
|
// newConstraints creates a new constraints object.
|
|
// The methods are *not* thread-safe; an external lock must be held if synchronization
|
|
// is required.
|
|
func newConstraints(rc *Resources) *constraints {
|
|
return &constraints{
|
|
rc: rc,
|
|
peers: make(map[peer.ID][]time.Time),
|
|
ips: make(map[string][]time.Time),
|
|
asns: make(map[string][]time.Time),
|
|
}
|
|
}
|
|
|
|
// AddReservation adds a reservation for a given peer with a given multiaddr.
|
|
// If adding this reservation violates IP constraints, an error is returned.
|
|
func (c *constraints) AddReservation(p peer.ID, a ma.Multiaddr) error {
|
|
c.mutex.Lock()
|
|
defer c.mutex.Unlock()
|
|
|
|
now := time.Now()
|
|
c.cleanup(now)
|
|
|
|
if len(c.total) >= c.rc.MaxReservations {
|
|
return errTooManyReservations
|
|
}
|
|
|
|
ip, err := manet.ToIP(a)
|
|
if err != nil {
|
|
return errors.New("no IP address associated with peer")
|
|
}
|
|
|
|
peerReservations := c.peers[p]
|
|
if len(peerReservations) >= c.rc.MaxReservationsPerPeer {
|
|
return errTooManyReservationsForPeer
|
|
}
|
|
|
|
ipReservations := c.ips[ip.String()]
|
|
if len(ipReservations) >= c.rc.MaxReservationsPerIP {
|
|
return errTooManyReservationsForIP
|
|
}
|
|
|
|
var asnReservations []time.Time
|
|
var asn string
|
|
if ip.To4() == nil {
|
|
asn, _ = asnutil.Store.AsnForIPv6(ip)
|
|
if asn != "" {
|
|
asnReservations = c.asns[asn]
|
|
if len(asnReservations) >= c.rc.MaxReservationsPerASN {
|
|
return errTooManyReservationsForASN
|
|
}
|
|
}
|
|
}
|
|
|
|
expiry := now.Add(validity)
|
|
c.total = append(c.total, expiry)
|
|
|
|
peerReservations = append(peerReservations, expiry)
|
|
c.peers[p] = peerReservations
|
|
|
|
ipReservations = append(ipReservations, expiry)
|
|
c.ips[ip.String()] = ipReservations
|
|
|
|
if asn != "" {
|
|
asnReservations = append(asnReservations, expiry)
|
|
c.asns[asn] = asnReservations
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *constraints) cleanupList(l []time.Time, now time.Time) []time.Time {
|
|
var index int
|
|
for i, t := range l {
|
|
if t.After(now) {
|
|
break
|
|
}
|
|
index = i + 1
|
|
}
|
|
return l[index:]
|
|
}
|
|
|
|
func (c *constraints) cleanup(now time.Time) {
|
|
c.total = c.cleanupList(c.total, now)
|
|
for k, peerReservations := range c.peers {
|
|
c.peers[k] = c.cleanupList(peerReservations, now)
|
|
}
|
|
for k, ipReservations := range c.ips {
|
|
c.ips[k] = c.cleanupList(ipReservations, now)
|
|
}
|
|
for k, asnReservations := range c.asns {
|
|
c.asns[k] = c.cleanupList(asnReservations, now)
|
|
}
|
|
}
|