]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Rate limit incoming IP prefixes
authorMatt Joiner <anacrolix@gmail.com>
Fri, 15 Jun 2018 12:38:11 +0000 (22:38 +1000)
committerMatt Joiner <anacrolix@gmail.com>
Fri, 15 Jun 2018 12:38:11 +0000 (22:38 +1000)
Lots of bad or dishonest incoming handshakes for unwanted torrents.

client.go

index 8c40226b2f7f85f4b04bdd3b281059acc3507fd9..d4c08422252e2975e6ecc62f3e6bcf6394cb10b2 100644 (file)
--- a/client.go
+++ b/client.go
@@ -65,8 +65,12 @@ type Client struct {
        torrents          map[metainfo.Hash]*Torrent
        // An aggregate of stats over all connections.
        stats ConnStats
+
+       acceptLimiter map[ipStr]int
 }
 
+type ipStr string
+
 func (cl *Client) BadPeerIPs() []string {
        cl.mu.RLock()
        defer cl.mu.RUnlock()
@@ -184,6 +188,7 @@ func NewClient(cfg *Config) (cl *Client, err error) {
                dopplegangerAddrs: make(map[string]struct{}),
                torrents:          make(map[metainfo.Hash]*Torrent),
        }
+       go cl.acceptLimitClearer()
        cl.initLogger()
        defer func() {
                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 {
                return true
        }
+       if cl.rateLimitAccept(rip) {
+               return true
+       }
        return cl.badPeerIPPort(rip, missinggo.AddrPort(ra))
 }
 
@@ -759,9 +767,15 @@ func (cl *Client) runReceivedConn(c *connection) {
        t, err := cl.receiveHandshakes(c)
        if err != nil {
                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
        }
        if t == nil {
+               cl.mu.Lock()
+               cl.onBadAccept(c.remoteAddr())
+               cl.mu.Unlock()
                return
        }
        cl.mu.Lock()
@@ -1239,3 +1253,36 @@ func (cl *Client) ListenAddrs() (ret []net.Addr) {
        })
        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
+}