2
0
mirror of synced 2025-02-24 14:48:27 +00:00

Rate limit incoming IP prefixes

Lots of bad or dishonest incoming handshakes for unwanted torrents.
This commit is contained in:
Matt Joiner 2018-06-15 22:38:11 +10:00
parent 2fb1c022f5
commit 8acfc5149b

View File

@ -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
}