Rate limit incoming IP prefixes
Lots of bad or dishonest incoming handshakes for unwanted torrents.
This commit is contained in:
parent
2fb1c022f5
commit
8acfc5149b
47
client.go
47
client.go
@ -65,8 +65,12 @@ type Client struct {
|
|||||||
torrents map[metainfo.Hash]*Torrent
|
torrents map[metainfo.Hash]*Torrent
|
||||||
// An aggregate of stats over all connections.
|
// An aggregate of stats over all connections.
|
||||||
stats ConnStats
|
stats ConnStats
|
||||||
|
|
||||||
|
acceptLimiter map[ipStr]int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ipStr string
|
||||||
|
|
||||||
func (cl *Client) BadPeerIPs() []string {
|
func (cl *Client) BadPeerIPs() []string {
|
||||||
cl.mu.RLock()
|
cl.mu.RLock()
|
||||||
defer cl.mu.RUnlock()
|
defer cl.mu.RUnlock()
|
||||||
@ -184,6 +188,7 @@ func NewClient(cfg *Config) (cl *Client, err error) {
|
|||||||
dopplegangerAddrs: make(map[string]struct{}),
|
dopplegangerAddrs: make(map[string]struct{}),
|
||||||
torrents: make(map[metainfo.Hash]*Torrent),
|
torrents: make(map[metainfo.Hash]*Torrent),
|
||||||
}
|
}
|
||||||
|
go cl.acceptLimitClearer()
|
||||||
cl.initLogger()
|
cl.initLogger()
|
||||||
defer func() {
|
defer func() {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -374,6 +379,9 @@ func (cl *Client) rejectAccepted(conn net.Conn) bool {
|
|||||||
if cl.config.DisableIPv6 && len(rip) == net.IPv6len && rip.To4() == nil {
|
if cl.config.DisableIPv6 && len(rip) == net.IPv6len && rip.To4() == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if cl.rateLimitAccept(rip) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return cl.badPeerIPPort(rip, missinggo.AddrPort(ra))
|
return cl.badPeerIPPort(rip, missinggo.AddrPort(ra))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -759,9 +767,15 @@ func (cl *Client) runReceivedConn(c *connection) {
|
|||||||
t, err := cl.receiveHandshakes(c)
|
t, err := cl.receiveHandshakes(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fmsg("error receiving handshakes: %s", err).AddValue(debugLogValue).Add("network", c.remoteAddr().Network()).Log(cl.logger)
|
log.Fmsg("error receiving handshakes: %s", err).AddValue(debugLogValue).Add("network", c.remoteAddr().Network()).Log(cl.logger)
|
||||||
|
cl.mu.Lock()
|
||||||
|
cl.onBadAccept(c.remoteAddr())
|
||||||
|
cl.mu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if t == nil {
|
if t == nil {
|
||||||
|
cl.mu.Lock()
|
||||||
|
cl.onBadAccept(c.remoteAddr())
|
||||||
|
cl.mu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cl.mu.Lock()
|
cl.mu.Lock()
|
||||||
@ -1239,3 +1253,36 @@ func (cl *Client) ListenAddrs() (ret []net.Addr) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cl *Client) onBadAccept(addr net.Addr) {
|
||||||
|
ip := maskIpForAcceptLimiting(missinggo.AddrIP(addr))
|
||||||
|
if cl.acceptLimiter == nil {
|
||||||
|
cl.acceptLimiter = make(map[ipStr]int)
|
||||||
|
}
|
||||||
|
cl.acceptLimiter[ipStr(ip.String())]++
|
||||||
|
}
|
||||||
|
|
||||||
|
func maskIpForAcceptLimiting(ip net.IP) net.IP {
|
||||||
|
if ip4 := ip.To4(); ip4 != nil {
|
||||||
|
return ip4.Mask(net.CIDRMask(24, 32))
|
||||||
|
}
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *Client) acceptLimitClearer() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-cl.closed.LockedChan(&cl.mu):
|
||||||
|
return
|
||||||
|
case <-time.After(15 * time.Minute):
|
||||||
|
cl.mu.Lock()
|
||||||
|
cl.acceptLimiter = nil
|
||||||
|
cl.mu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *Client) rateLimitAccept(ip net.IP) bool {
|
||||||
|
// return true
|
||||||
|
return cl.acceptLimiter[ipStr(maskIpForAcceptLimiting(ip).String())] >= 10
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user