Commits

EGh5  committed 6483824

v. 1.6.0 for django 1.4

  • Participants
  • Parent commits 1551ffd

Comments (0)

Files changed (3)

File doorkeeper/__init__.py

 """
 Django-doorkeeper helps to deal with malicious url requests
 """
-version = (1,5,6)
+version = (1,6,0)
 __version__ = '.'.join(map(str, version))

File doorkeeper/middleware.py

 from doorkeeper.models import BotRecord
 from django.conf import settings
 from utils import MemClient
-
+try:
+    from django.utils.timezone import now as django_now
+except ImportError:
+    django_now=datetime.datetime.now
 import logging
 log = logging.getLogger(__name__)
 
         dd=hashlib.md5()
         dd.update(shash)
         memhash=dd.hexdigest()
+        memhash0= memhash+"0"
 
         if MEMCACHE:                                 # ####  path for MEMCACHED (fast)
             mc=MemClient(MEMCACHE)
             br=mc.get(memhash)
             if br is None:
                 return                               # ==>> exit for 99.9% requests
-            
-            now=datetime.datetime.now()
-            
+            bd = mc.get(memhash0)
+            if bd is not None and bd >PATIENCE:      # for massive attack bounce
+                log.info("bd=%s > PATIENCE=%s"% (bd,PATIENCE))
+                raise Http404
+            now=django_now()
             if br.detention_upto:                    # check detention end time
-                if br.detention_upto> now:           # if it is a fresh banned client
-                    log.info("Memcached middleware  %s penalty %s, detention %s for %s" % (shash,br.penalty_count,
-                         br.detention_upto, request.path))
-                    raise Http404()                  # ==>> bounce - it's active bad bot!
-                else:
-                    if br.penalty_count > PATIENCE:  # for old banned client
-                        br.penalty_count-=PATIENCE   # forgiving them partly
-                        br.save()
-                        mc.add(memhash,br,time=TERM*2)
-                    pass                             # ==>> it was a bad bot, maybe not now?
-
-        else:                                        # ### path for DB-driven (slow)
-            try:
-                br=BotRecord.objects.get(bot_hash=shash) # if client exists in BotRecords
-                now=datetime.datetime.now()
-                if br.detention_upto:                    # check detention end time
+                try:
                     if br.detention_upto> now:           # if it is a fresh banned client
-                        raise Http404()                  # bounce - it's active bad bot!
+                        log.info("Memcached, %s penalty %s, detention %s for %s" %
+                                 (shash,br.penalty_count, br.detention_upto, request.path))
+                        raise Http404()                  # ==>> bounce - it's active bad bot!
                     else:
                         if br.penalty_count > PATIENCE:  # for old banned client
                             br.penalty_count-=PATIENCE   # forgiving them partly
-                            br.save()                    # ==>> it was a bad bot, maybe not now?
-                        pass
+                            br.save()
+                            mc.add(memhash,br,time=TERM*2)
+                            bd=0
+                            mc.set(memhash0,bd,time=TERM*2)
+                        pass                             # ==>> it was a bad bot, maybe not now?
+                except TypeError as er:
+                    log.error("%s: %s > %s  %s" %(er,br.detention_upto,now,request.path))
+                    return
+        else:                                        # ### path for DB-driven (slow)
+            try:
+                br=BotRecord.objects.get(bot_hash=shash) # if client exists in BotRecords
+                now=django_now()
+                if br.detention_upto:                    # check detention end time
+                    try:
+                        if br.detention_upto> now:           # if it is a fresh banned client
+                            raise Http404()                  # bounce - it's active bad bot!
+                        else:
+                            if br.penalty_count > PATIENCE:  # for old banned client
+                                br.penalty_count-=PATIENCE   # forgiving them partly
+                                br.save()                    # ==>> it was a bad bot, maybe not now?
+                            pass
+                    except TypeError as er:
+                        log.error("%s: %s > %s  %s" %(er,br.detention_upto,now,request.path))
+                        return
             except BotRecord.DoesNotExist:               # ==>> exit for most requests
                 pass

File doorkeeper/views.py

-# views for django-doorkeeper
-# Eugene Gavrish
-# 
-
+# Create your views here.
 from django.http import Http404
+
 from models import BotRecord
-import datetime, hashlib
+import datetime
 from django.conf import settings
+import hashlib
 from utils import MemClient
+try:
+    from django.utils.timezone import now as django_now
+except ImportError:
+    django_now=datetime.datetime.now
+
 
 import logging
 log = logging.getLogger(__name__)
     """
 
     View to register suspicious client and raise Http404
-    if bad request frequency is higher then PATIENCE
-    counter BotRecord.penalty_count increases until threshold.
+    if bad request frequency is higher then PATIENCE.
+    Counter BotRecord.penalty_count increases until threshold.
     Then detention_upto is set to future and middleware begins bouncing
     this client.
-
+    Ksi variable = minimum interval for next request (humans should be slow! :)
     """
     sagent = request.META.get('HTTP_USER_AGENT',"n/a")
     saddr = request.META.get('REMOTE_ADDR',"n/a")
     dd    = hashlib.md5()
     dd.update(shash)
     memhash = dd.hexdigest()
-
+    memhash0= memhash+"0"
+    bd=0
+    ksi  = datetime.timedelta(0,2)
+    now  = django_now()
     try:
         if MEMCACHE:
-            mc=MemClient(MEMCACHE)
-            br=mc.get(memhash)
-            
+            mc = MemClient(MEMCACHE)
+            bd = mc.get(memhash0)
+            """
+            if-block below is for massive malicious request attack. The goal is
+            to record in memcache variable bd as soon as possible for next
+            instance of this view.
+            """
+            if bd is None:
+                bd=1
+                mc.add(memhash0,bd,TERM)
+            else:
+                bd+=1
+                mc.set(memhash0,bd)
+            br = mc.get(memhash)
+
             if br is None:
-                br=BotRecord.objects.get(bot_hash=shash)
+                br = BotRecord.objects.get(bot_hash=shash)
                 mc.add(memhash,br,time=TERM*2)
+            else:
+                br.penalty_count=bd
+                mc.set(memhash,br)
         else:
-            br=BotRecord.objects.get(bot_hash=shash)
-        now=datetime.datetime.now()
-        delta=datetime.timedelta(0,TERM)
+            br = BotRecord.objects.get(bot_hash=shash)
+        delta= datetime.timedelta(0,TERM)
         if br.last_date+delta > now:
             br.penalty_count+=1
             if br.penalty_count > PATIENCE:
                 br.detention_upto=now+delta
                 br.jail_count+=1
+            else:
+                br.detention_upto=now+ksi;
         else:
             if br.penalty_count > PATIENCE:  # for old banned client
                 br.penalty_count-=PATIENCE   # forgiving them partly
     except BotRecord.DoesNotExist:
-        br=BotRecord.objects.create(bot_hash=shash,bot_name=sagent, bot_adr=saddr)
+        br=BotRecord.objects.create(bot_hash=shash,bot_name=sagent, bot_adr=saddr,
+                                      detention_upto=now+ksi,penalty_count=1)
+    if (bd > 1) and (bd > br.penalty_count) : br.penalty_count=bd
     br.save()
-    if MEMCACHE: 
+    if MEMCACHE:
         mc.set(memhash,br)
-        log.info("Memcached view %s, penalty %s, detention %s" % (shash,br.penalty_count,br.detention_upto))
+        log.info("path:%s Memcached view %s, penalty %s, detention %s" %
+                 (request.path, shash,br.penalty_count,br.detention_upto))
     raise Http404()