"Fossies" - the Fresh Open Source Software Archive

Member "mod-dosblock/mod_dosblock_module.c" (27 Jul 2011, 25785 Bytes) of package /linux/www/apache_httpd_modules/old/mod_dosblock-v1.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* Copyright 2011 Google Inc. All Rights Reserved.
    2 
    3  * Licensed under the Apache License, Version 2.0 (the "License");
    4  * you may not use this file except in compliance with the License.
    5  * You may obtain a copy of the License at
    6 
    7  *  http://www.apache.org/licenses/LICENSE-2.0
    8 
    9  * Unless required by applicable law or agreed to in writing, software
   10  * distributed under the License is distributed on an "AS IS" BASIS,
   11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12  * See the License for the specific language governing permissions and
   13  * limitations under the License.
   14  */
   15 
   16 #include "httpd.h"
   17 #include "http_config.h"
   18 #include "http_core.h"
   19 #include "http_log.h"
   20 #include "http_main.h"
   21 #include "http_protocol.h"
   22 #include "http_request.h"
   23 #include "util_script.h"
   24 #include "http_connection.h"
   25 
   26 #include "apr_global_mutex.h"
   27 #include "apr_strings.h"
   28 #include "ap_config.h"
   29 #include "apr_time.h"
   30 #if APR_HAVE_SYS_TYPES_H
   31 #include <sys/types.h>
   32 #endif
   33 #if APR_HAVE_UNISTD_H
   34 #include <unistd.h>
   35 #endif
   36 
   37 #define RULEURL "url"
   38 #define RULEHEADER "header"
   39 #define ARSIZE 300 /* No of seconds that we use to calculate the rate. Default is rate over 5 mins */
   40 #define MAXRULE 20 /* Max number of dos rules that can be configured */
   41 
   42 #ifdef AP_NEED_SET_MUTEX_PERMS
   43   #include "unixd.h"
   44 #endif
   45 
   46 /*--------------------------------------------------------------------------
   47  * mod_dosblock was developed to fill the need for dos protection at the http
   48  * layer. We hook at the post_read_request phase to catch problems early.  It
   49  * can be  configured to act on the url or the http header. It does not the
   50  * support combining two or more subrules. You can define a url based subrule
   51  * using the following syntax
   52  *
   53  * DosBlockUrl <name of the  url subrule> <pattern>
   54  *
   55  * example
   56  *
   57  * DosBlockUrl myurlrule /test
   58  *
   59  * Header based subrule can be defined as follows
   60  * DosBlockHeader <name of the header subrule> <headername>  <pattern>
   61  *
   62  * example
   63  *
   64  * DosBlockHeader myheaderrule User-Agent mozilla
   65  *
   66  * Then you use the following syntax to do the real blocking
   67  * DosBlockRule <dos rule name>:<name of the subrule> <threshold rate (hits per
   68  * sec)> <time to blocki ( in secs)>
   69  *
   70  * example
   71  *
   72  * DosBlockRule dosblock_header:myheaderrule 2 60
   73  *
   74  * A complete example
   75  *
   76  * DosBlockUrl myurlrule /test
   77  * DosBlockRule blocktest:myurlrule 50 120
   78  *
   79  * In case you want to enable debugging you can set
   80  *
   81  * DosBlockVerbose On
   82  *
   83  * Its off by default
   84  *
   85  * I plan to add support for combining subrules in a subsequent release
   86  *
   87  ---------------------------------------------------------------------------*/
   88 
   89 apr_shm_t *dosblockipc_shm[MAXRULE]; /* Array of pointers to shared memory blocks */
   90 char *shmfilename; /* Shared memory file name, used on some systems */
   91 char *mutex_filename;
   92 apr_global_mutex_t *dosblockipc_mutex[MAXRULE]; /* Array of mutex locks around shared memory segments */
   93 
   94 /* Config related data structure */
   95 typedef struct {
   96     apr_table_t *urlrules;
   97     apr_hash_t *headerrules;
   98     apr_table_t *ruletype;          /* Table to store the type of the subrule i.e(url or header) */
   99     apr_table_t *dosrulemap;        /* Mapping between the dos rule and the subrule */
  100     apr_hash_t *dosrules;           /* This hash map stores in its value object of type dosrulestruct */
  101     apr_hash_t *dosrule_shm_map;    /* Mapping between the dos rule and the shared mem segment */
  102     apr_table_t *dosrule_mutex_map; /* Mapping between the dos rule and the mutext */
  103     int verbosity;                  /* Used to log messages  based on what we have here */
  104 }dosblock_cfg;
  105 
  106 /* struct to hold info about header based subrule.
  107  * Note that we do not need any struct for url based subrule as a normal table is sufficient.
  108  */
  109 
  110 typedef struct {
  111     char *headername;
  112     char *headerpattern;
  113 }headerrulestruct;
  114 
  115 /* Struct to hold info about the actual dos rule */
  116 typedef struct {
  117     char *subrule;
  118     char *threshold;
  119     char *timetoblock;
  120 }dosrulestruct;
  121 
  122 typedef struct dosblock_hits {
  123     apr_time_t t;
  124     apr_int64_t counter;
  125 }dosblock_hits;
  126 
  127 typedef struct dosblock_status {
  128     apr_time_t t;
  129     int isblocked;
  130     int rate_when_blocked;
  131 }dosblock_status;
  132 
  133 /* Data structure for shared memory block */
  134 typedef struct dosblockipc_data {
  135     dosblock_hits dh[ARSIZE];
  136     dosblock_status ds;
  137     int next;
  138 }dosblockipc_data;
  139 
  140 dosblockipc_data *base = NULL;
  141 
  142 module AP_MODULE_DECLARE_DATA mod_dosblock_module;
  143 
  144 /* Set up all our data structs in the pre config phase */
  145 static void * dosblock_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) {
  146     dosblock_cfg *cfg = apr_pcalloc(p, sizeof(*cfg));
  147 
  148     if (!cfg)
  149         return NULL;
  150     cfg->urlrules = apr_table_make(p, MAXRULE);
  151     cfg->headerrules = apr_hash_make(p);
  152     cfg->ruletype = apr_table_make(p, MAXRULE);
  153     cfg->dosrulemap = apr_table_make(p, MAXRULE);
  154     cfg->dosrules = apr_hash_make(p);
  155     cfg->dosrule_shm_map = apr_hash_make(p);
  156     cfg->dosrule_mutex_map = apr_table_make(p, MAXRULE);
  157 
  158     return cfg;
  159 }
  160 
  161 /* Initialise the requisite data structs for our url based dos subrule
  162  * @param word1 The name of the subrule
  163  * @param word2 The pattern
  164  */
  165 static void *dosblock_url_config(cmd_parms *cmd, void *mconfig, char *word1, char *word2) {
  166     server_rec *s = cmd->server;
  167     dosblock_cfg *cfg = (dosblock_cfg *)ap_get_module_config(s->module_config, &mod_dosblock_module);
  168 
  169     if(word1 !=NULL && word2 !=NULL)
  170       {
  171         /* We test the regexp and populate the table only on success */
  172         if (ap_pregcomp(cmd->pool, word2, AP_REG_EXTENDED) != NULL )
  173             {
  174              apr_table_set(cfg->urlrules, word1, word2);
  175              apr_table_set(cfg->ruletype, word1, RULEURL);
  176             }
  177         else {
  178              ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Failed to compile regexp %s", word2);
  179             }
  180       }
  181 
  182     return NULL;
  183 }
  184 
  185 /* Initialise the requisite data structs for our header based dos subrule
  186  * @param word1 The name of the subrule
  187  * @param word2 The http header to match
  188  * @paramm word3 The pattern
  189  */
  190 static void *dosblock_header_config(cmd_parms *cmd, void *mconfig, char *word1, char *word2, char *word3) {
  191 
  192     server_rec *s = cmd->server;
  193     dosblock_cfg *cfg = (dosblock_cfg *)ap_get_module_config(s->module_config, &mod_dosblock_module);
  194 
  195     if(word1 !=NULL && word2 !=NULL && word3 !=NULL)
  196      {
  197        headerrulestruct *h = NULL;
  198        h = apr_palloc(cmd->pool, sizeof(headerrulestruct));
  199        h->headername = word2;
  200        h->headerpattern = word3;
  201 
  202        /* We test the regexp and populate the table,hash only on success */
  203        if (ap_pregcomp(cmd->pool, word3, AP_REG_EXTENDED) != NULL )
  204           {
  205            apr_hash_set(cfg->headerrules, word1, APR_HASH_KEY_STRING, h);
  206            apr_table_set(cfg->ruletype, word1, RULEHEADER);
  207           }
  208        else {
  209            ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Failed to compile regexp %s", word3);
  210        }
  211 
  212      }
  213     return NULL;
  214 }
  215 
  216 /* Initialise the requisite data structs for the real dos rule
  217  * @param word1 The "dos rule name: subrule" format
  218  * @param word2 The threshold rate
  219  * @param word3 Time (epoch) till blockage
  220  * */
  221 static void *dosblockrule_config(cmd_parms *cmd, void *mconfig, char *word1, char *word2, char *word3) {
  222     server_rec *s = cmd->server;
  223     char  *dosrulename, *subrule, *saveptr1;
  224     dosblock_cfg *cfg = (dosblock_cfg *)ap_get_module_config(s->module_config, &mod_dosblock_module);
  225 
  226     if(word1 !=NULL && word2 !=NULL && word3 !=NULL)
  227       {
  228        dosrulename = apr_strtok(word1, ":", &saveptr1);
  229        subrule = apr_strtok(NULL, ":", &saveptr1);
  230        dosrulestruct *d = NULL;
  231        d = apr_palloc(cmd->pool, sizeof(dosrulestruct));
  232        d->subrule = subrule;
  233        d->threshold = word2;
  234        d->timetoblock = word3;
  235        /* apr_table_set ensures that the same rule is over-written, while for
  236         * apr_hash_set we employ the following hack
  237         */
  238        apr_table_set(cfg->dosrulemap, dosrulename, subrule);
  239        if (apr_hash_get(cfg->dosrules, dosrulename, APR_HASH_KEY_STRING) != NULL) {
  240          /* There is an entry. Delete it. This is a hack so that we only store
  241           * the latest entry of the same rule
  242           */
  243             apr_hash_set(cfg->dosrules, dosrulename, APR_HASH_KEY_STRING, NULL);
  244 
  245         }
  246        apr_hash_set(cfg->dosrules, dosrulename, APR_HASH_KEY_STRING, d);
  247      }
  248     return NULL;
  249 }
  250 
  251 /* Set the verbosity flag
  252  */
  253 static const char *dosblock_verbosityflag(cmd_parms *cmd, void *mconfig, int bool) {
  254     server_rec *s = cmd->server;
  255     dosblock_cfg *cfg = (dosblock_cfg *)ap_get_module_config(s->module_config, &mod_dosblock_module);
  256     cfg->verbosity = bool;
  257     return NULL;
  258 }
  259 
  260 static  command_rec mod_dosblock_cmds[] = {
  261      AP_INIT_TAKE2("DosBlockUrl", dosblock_url_config, NULL, RSRC_CONF, "Url pattern to look for" ),
  262      AP_INIT_TAKE3("DosBlockHeader", dosblock_header_config, NULL, RSRC_CONF, "Header pattern to look for" ),
  263      AP_INIT_TAKE3("DosBlockRule", dosblockrule_config, NULL, RSRC_CONF, "Actual dos rule" ),
  264      AP_INIT_FLAG("DosBlockVerbose", dosblock_verbosityflag, NULL, RSRC_CONF, "Sets the verbosity flag" ),
  265 
  266     { NULL }
  267 };
  268 
  269 /*
  270  * Clean up the shared memory blocks. This function is registered as
  271  * cleanup function for the configuration pool, which gets called
  272  * on restarts. It assures that the new children will not talk to a stale
  273  * shared memory segments.
  274  */
  275 static apr_status_t shm_cleanup_wrapper() {
  276     int i;
  277 
  278     for (i=0; i<MAXRULE; i++) {
  279        if (dosblockipc_shm[i]) {
  280        apr_shm_destroy((apr_shm_t *)dosblockipc_shm[i]);
  281        }
  282     }
  283     return OK;
  284 }
  285 
  286 
  287 /* Merge vserver configs */
  288 static void *dosblock_config_server_merge(apr_pool_t *p, void *base_, void *vhost_) {
  289 
  290      /* We do not support vhosts. The module configs are in the main apache conf */
  291      return base_;
  292 }
  293 
  294 /*
  295  * This routine is called in the parent, so we'll set up the shared
  296  * memory segments and mutexs here.
  297  */
  298 static int dosblock_post_config(apr_pool_t *pconf, apr_pool_t *plog,
  299                              apr_pool_t *ptemp, server_rec *s)
  300 {
  301     void *data; /* These two help ensure that we only init once. */
  302     const char *userdata_key;
  303     apr_status_t rs;
  304     const char *tempdir;
  305     dosblockipc_data *base;
  306     dosblock_cfg *cfg = (dosblock_cfg *)ap_get_module_config(s->module_config, &mod_dosblock_module);
  307     /*
  308      * The following checks if this routine has been called before.
  309      * This is necessary because the parent process gets initialized
  310      * a couple of times as the server starts up, and we don't want
  311      * to create any more mutexes and shared memory segments than
  312      * we're actually going to use.
  313      *
  314      * The key needs to be unique for the entire web server, so put
  315      * the module name in it.
  316      */
  317     userdata_key = "dosblock_ipc_init_module";
  318     apr_pool_userdata_get(&data, userdata_key, s->process->pool);
  319 
  320     if (!data) {
  321         /*
  322          * If no data was found for our key, this must be the first
  323          * time the module is initialized. Put some data under that
  324          * key and return.
  325          */
  326         apr_pool_userdata_set((const void *) 1, userdata_key,
  327                               apr_pool_cleanup_null, s->process->pool);
  328         return OK;
  329     }
  330 
  331     /*
  332      * The shared memory allocation routines take a file name.
  333      * Depending on system-specific implementation of these
  334      * routines, that file may or may not actually be created. We'd
  335      * like to store those files in the operating system's designated
  336      * temporary directory, which APR can point us to.
  337      */
  338     rs = apr_temp_dir_get(&tempdir, pconf);
  339     if (APR_SUCCESS != rs) {
  340         ap_log_error(APLOG_MARK, APLOG_ERR, rs, s,
  341                      "Failed to find temporary directory");
  342         return HTTP_INTERNAL_SERVER_ERROR;
  343     }
  344 
  345     /* Create the shared memory segments. We also populate a dosrule to shared
  346      * memory mapping table with all the shared memory segments
  347      */
  348 
  349     const apr_array_header_t *tarr = apr_table_elts(cfg->dosrulemap);
  350     const apr_table_entry_t *telts = (const apr_table_entry_t*)tarr->elts;
  351     int i;
  352 
  353     for (i = 0; i < tarr->nelts; ++i) {
  354      /*
  355       * Create a unique filename using our pid. This information is
  356       * stashed in the global variable so the children inherit it.
  357       */
  358        shmfilename = apr_psprintf(pconf, "%s/httpd_shm_%s.%ld", tempdir,
  359                                telts[i].key, (long int)getpid());
  360        mutex_filename = apr_psprintf(pconf, "%s/httpd_mutex_%s.%ld", tempdir,
  361                                telts[i].key, (long int)getpid());
  362 
  363        /* Now create that shm segment. We prefer anonymous shm */
  364        rs = apr_shm_create(&dosblockipc_shm[i], sizeof(dosblockipc_data),
  365                         NULL, pconf);
  366        if (APR_ENOTIMPL == rs) {
  367          rs = apr_shm_create(&dosblockipc_shm[i], sizeof(dosblockipc_data),
  368                         (const char *) shmfilename, pconf);
  369          }
  370        if (APR_SUCCESS != rs) {
  371            ap_log_error(APLOG_MARK, APLOG_ERR, rs, s,
  372                        "Failed to create shared memory segment on file %s",
  373                        shmfilename);
  374            return HTTP_INTERNAL_SERVER_ERROR;
  375        }
  376        apr_hash_set(cfg->dosrule_shm_map, telts[i].key, APR_HASH_KEY_STRING, apr_psprintf(pconf, "%d",i));
  377        if (cfg->verbosity)
  378           ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Dos Rule configured is %s", telts[i].key);
  379 
  380        base = (dosblockipc_data *)apr_shm_baseaddr_get(dosblockipc_shm[i]);
  381        /* Now initialise the array of structs. Zero it out */
  382        base->ds.t = 0;
  383        base->ds.isblocked = 0;
  384        base->ds.rate_when_blocked = 0;
  385        base->next = 0;
  386        int j;
  387        for (j=0; j<ARSIZE; j++) {
  388          base->dh[j].t = 0;
  389          base->dh[j].counter = 0;
  390 
  391        }
  392        /* Create global mutex */
  393 
  394        rs = apr_global_mutex_create(&dosblockipc_mutex[i], mutex_filename, APR_LOCK_DEFAULT, pconf);
  395       if (APR_SUCCESS != rs) {
  396           return HTTP_INTERNAL_SERVER_ERROR;
  397        }
  398        #ifdef AP_NEED_SET_MUTEX_PERMS
  399           rs = unixd_set_global_mutex_perms(dosblockipc_mutex[i]);
  400           if (rs != APR_SUCCESS) {
  401               ap_log_error(APLOG_MARK, APLOG_CRIT, rs, s,
  402                  "mod_dosblock: Parent could not set permissions "
  403                  "on shared memory; check User and Group directives");
  404               return rs;
  405            }
  406        #endif
  407 
  408       apr_table_set(cfg->dosrule_mutex_map, telts[i].key, mutex_filename);
  409 
  410     }
  411     /*
  412      * Destroy the shm segment when the configuration pool gets destroyed. This
  413      *happens on server restarts. The parent will then (above) allocate a new
  414      * shm segment that the new children will bind to.
  415      */
  416 
  417     /*
  418      apr_pool_cleanup_register(pconf, NULL, shm_cleanup_wrapper(),
  419                               apr_pool_cleanup_null);
  420     */
  421      return OK;
  422 }
  423 
  424 /*
  425  * This routine gets called when a child inits. We use it to attach
  426  * to the shared memory segments, and reinitialize the corresponding mutex.
  427  */
  428 static void dosblock_child_init(apr_pool_t *p, server_rec *s)
  429 {
  430     apr_status_t rs ;
  431     const apr_table_entry_t *dosrule_mutex_map_elts = NULL;
  432     const apr_array_header_t *dosrule_mutex_map_arr = NULL;
  433     /*
  434      * Re-open the mutexes for the child. Note we're reusing
  435      * the mutex pointer global here.
  436      */
  437      dosblock_cfg *cfg = (dosblock_cfg *)ap_get_module_config(s->module_config, &mod_dosblock_module);
  438      dosrule_mutex_map_arr = apr_table_elts(cfg->dosrule_mutex_map);
  439 
  440      if (dosrule_mutex_map_arr) {
  441          dosrule_mutex_map_elts = (const apr_table_entry_t *)dosrule_mutex_map_arr->elts;
  442          int i = 0;
  443          for (i=0; i<dosrule_mutex_map_arr->nelts; ++i)
  444            {
  445             rs = apr_global_mutex_child_init(&dosblockipc_mutex[i], dosrule_mutex_map_elts[i].val, p);
  446             if (APR_SUCCESS != rs) {
  447                 ap_log_error(APLOG_MARK, APLOG_CRIT, rs, s,
  448                          "Failed to reopen mutex %s in child",
  449                          dosblockipc_mutex[i]);
  450                 /* There's really nothing else we can do here, since This
  451                  * routine doesn't return a status. If this ever goes wrong,
  452                  * it will turn Apache into a fork bomb. Let's hope it never
  453                  * will.
  454                 */
  455                exit(1); /* Ugly, but what else? */
  456              }
  457           }
  458      }
  459 }
  460 
  461 /* Here-in lies the meat */
  462 static int dosblock_main(request_rec *r) {
  463     const apr_table_entry_t *dosrulemap_elts = NULL;
  464     const apr_array_header_t *dosrulemap_arr = NULL;
  465     char *subrule=NULL, *dosrulematch=NULL, *urlpattern=NULL;
  466     char *req_header = NULL;
  467     int matchfound = 0;
  468     int gotlock = 0;
  469     dosblockipc_data *base = NULL;
  470     apr_status_t rs;
  471     dosblock_cfg *cfg = (dosblock_cfg *)ap_get_module_config(r->server->module_config, &mod_dosblock_module);
  472 
  473     /* Here we try to find if the request matches a dos rule */
  474     dosrulemap_arr = apr_table_elts(cfg->dosrulemap);
  475 
  476     if (dosrulemap_arr) {
  477         dosrulemap_elts = (const apr_table_entry_t *)dosrulemap_arr->elts;
  478         int i;
  479         for (i=0; i<dosrulemap_arr->nelts; ++i)
  480          {
  481            subrule = dosrulemap_elts[i].val;
  482            char *subrule_type =  (char *)apr_table_get(cfg->ruletype, subrule);
  483            if (subrule_type == NULL)
  484              continue;
  485            /* Check if it is a url based subrule */
  486            if (0 == apr_strnatcmp(subrule_type, RULEURL))
  487               {
  488                urlpattern = (char *)apr_table_get(cfg->urlrules, subrule);
  489                if (urlpattern == NULL)
  490                  continue;
  491                ap_regex_t *pattern = ap_pregcomp(r->pool, urlpattern, AP_REG_EXTENDED);
  492                if (0 == ap_regexec(pattern, r->uri, 0, NULL, 0))
  493                /* This is where the dos url subrule would match */
  494                  {
  495                    dosrulematch = dosrulemap_elts[i].key;
  496                    matchfound = 1;
  497                    break;
  498                  }
  499               }
  500            /* Check if it is a header based subrule */
  501             else if (0 == apr_strnatcmp(subrule_type, RULEHEADER))
  502              {
  503               headerrulestruct *h = NULL;
  504               h = apr_hash_get(cfg->headerrules, subrule, APR_HASH_KEY_STRING);
  505               if (h == NULL)
  506                 continue;
  507               req_header = (char *)apr_table_get(r->headers_in, h->headername);
  508               if (req_header == NULL)
  509                 continue;
  510               ap_regex_t *pattern = ap_pregcomp(r->pool, h->headerpattern, AP_REG_EXTENDED);
  511               if (0 == ap_regexec(pattern, req_header, 0, NULL, 0))
  512                /* This is where the dos header subrule would match */
  513                 {
  514                   dosrulematch = dosrulemap_elts[i].key;
  515                   matchfound = 1;
  516                   break;
  517                 }
  518              }
  519          }
  520        }
  521 
  522     if (matchfound && dosrulematch) {
  523       int blocked = 0;
  524       /* apr_table_set(r->headers_out, "DOSRULE_MATCHED", dosrulematch);*/
  525       /*  Check if we have the corresponding shared memory segment for
  526        *  the matching dos rule. If not we do not go further.
  527        */
  528       if (!apr_hash_get(cfg->dosrule_shm_map, dosrulematch, APR_HASH_KEY_STRING))
  529        {
  530           return DECLINED;
  531         }
  532       apr_int64_t index = apr_atoi64(apr_hash_get(cfg->dosrule_shm_map, dosrulematch, APR_HASH_KEY_STRING));
  533 
  534       /* Take the mutex lock here. Be careful of not 'returning' before releasing the lock*/
  535       rs = apr_global_mutex_lock(dosblockipc_mutex[index]);
  536       if (APR_SUCCESS == rs) {
  537           gotlock = 1;
  538       }
  539       else {
  540         /* Some error, log and bail */
  541         ap_log_error(APLOG_MARK, APLOG_ERR, rs, r->server, "Child %ld failed to acquire lock", (long int)getpid());
  542       }
  543       base = (dosblockipc_data *)apr_shm_baseaddr_get(dosblockipc_shm[index]);
  544       /* check if the Dos rule is already blocked */
  545       if (base->ds.isblocked)
  546        {
  547         /* The dos rule is blocked at this moment. Need to check the time stamp
  548          * (time till blockage) and act accordingly
  549          */
  550         apr_time_t time_now = apr_time_now();
  551         apr_time_t time_to_blockage = base->ds.t;
  552         /* apr_table_set(r->headers_out, "Blocked till", apr_psprintf(r->pool, "%d",time_to_blockage)); */
  553         if(cfg->verbosity)
  554            ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Dos rule %s is blocked", dosrulematch);
  555         if (time_now < time_to_blockage)
  556          {
  557           /* Keep blocking */
  558            blocked = 1;
  559            if(cfg->verbosity)
  560              ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Keep dos rule %s blocked", dosrulematch);
  561 
  562          }
  563         else {
  564           /* Time to unblock */
  565            base->ds.isblocked = 0;
  566            base->ds.t = 0;
  567            /* apr_table_set(r->headers_out, "Time-to-unblock", "Unblock"); */
  568            if(cfg->verbosity)
  569              ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Time to unblock dos rule %s", dosrulematch);
  570 
  571           }
  572       }
  573       /* Here we age entries, try to account for the matched hit, calculate the
  574        * rate and take some action if needed.
  575        */
  576       int i;
  577       apr_int64_t sum_counter = 0;
  578       int hit_accounted = 0;
  579 
  580       /* Loop through the array of structs */
  581       for (i=0; i<ARSIZE; i++) {
  582         if (base->dh[i].t) {
  583           if ((r->request_time - base->dh[i].t)/APR_USEC_PER_SEC > ARSIZE ) {
  584             /* Ageing entries */
  585              base->dh[i].t = 0;
  586              base->dh[i].counter = 0;
  587              if(cfg->verbosity)
  588                ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Ageing entry for dos rule %s", dosrulematch);
  589              continue;
  590            }
  591           if (base->dh[i].t/APR_USEC_PER_SEC == r->request_time/APR_USEC_PER_SEC )
  592             {
  593               /* There is already an entry for this sec. Increment the corresponding
  594                * counter
  595                */
  596               base->dh[i].counter++;
  597               sum_counter+= base->dh[i].counter;
  598               hit_accounted = 1;
  599               /*apr_table_set(r->headers_out, "Entry-for-this-sec", "Exists"); */
  600               if(cfg->verbosity)
  601                 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "We have an Entry-for-this-sec for dos rule %s", dosrulematch);
  602              continue;
  603             }
  604           sum_counter+= base->dh[i].counter;
  605           }
  606         }
  607 
  608       /* Add an element in our array of structs for this second if the hit was not accounted above */
  609       if (! hit_accounted) {
  610         if(cfg->verbosity)
  611           ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Hit is not accounted for dos rule %s", dosrulematch);
  612         if ((ARSIZE - base->next) ==  0)
  613           base->next = 0;
  614         base->dh[base->next].t = r->request_time;
  615         base->dh[base->next].counter = 1;
  616         sum_counter+= base->dh[base->next].counter;
  617         base->next++;
  618         /*apr_table_set(r->headers_out, "Entry-for-this-sec", "Does-not-Exist");*/
  619         if(cfg->verbosity)
  620           ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "We do not have an entry for this second (dos rule %s) and sum of counter is %" APR_INT64_T_FMT, dosrulematch, sum_counter);
  621       }
  622 
  623       if ( ! blocked) {
  624         float rate = (float)sum_counter/ARSIZE;
  625         /* Get the configured rate threshold */
  626         dosrulestruct *d = apr_hash_get(cfg->dosrules, dosrulematch, APR_HASH_KEY_STRING);
  627         if(cfg->verbosity) {
  628           ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Non Blocked dos rule %s sum of counter is %" APR_INT64_T_FMT, dosrulematch, sum_counter);
  629           ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Non Blocked dos rule %s rate is %f", dosrulematch, rate);
  630           ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Non Blocked dos rule %s configured  rate is %" APR_INT64_T_FMT, dosrulematch, apr_atoi64(d->threshold));
  631         }
  632         if (rate > apr_atoi64(d->threshold))
  633          {
  634            /* Block it */
  635            base->ds.isblocked = 1;
  636            base->ds.t = (apr_time_now() + (apr_atoi64(d->timetoblock)*APR_USEC_PER_SEC));
  637            base->ds.rate_when_blocked = rate;
  638            if(cfg->verbosity) {
  639              ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Non Blocked dos rule %s getting blocked after rate calulation", dosrulematch);
  640              ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Non Blocked dos rule %s getting blocked till %" APR_TIME_T_FMT, dosrulematch, base->ds.t);
  641            }
  642            blocked = 1;
  643          }
  644       }
  645 
  646       /* Release the lock. We have to be careful of not 'returning' before
  647        * releasing the lock
  648        */
  649       if (gotlock)
  650         rs = apr_global_mutex_unlock(dosblockipc_mutex[index]);
  651       /* Swallowing the result because what are we going to do with it at
  652        * this stage
  653        */
  654       if (blocked)
  655         return HTTP_FORBIDDEN;
  656    }
  657     else {
  658       /* apr_table_set(r->headers_out, "DOSRULE_MATCHED", "None");*/
  659     }
  660 
  661     return DECLINED;
  662 }
  663 
  664 static void register_hooks(apr_pool_t *p) {
  665    ap_hook_post_config(dosblock_post_config, NULL, NULL, APR_HOOK_MIDDLE);
  666    ap_hook_child_init(dosblock_child_init, NULL, NULL, APR_HOOK_MIDDLE);
  667    ap_hook_post_read_request(dosblock_main, NULL, NULL, APR_HOOK_FIRST);
  668 
  669 }
  670 
  671 module AP_MODULE_DECLARE_DATA mod_dosblock_module = {
  672     STANDARD20_MODULE_STUFF,
  673     NULL,                         /* create per-directory config structure */
  674     NULL,                         /* merge per-directory config structures */
  675     dosblock_config,              /* create per-server config structure */
  676     dosblock_config_server_merge, /* merge per-server config structures */
  677     mod_dosblock_cmds,            /* command table */
  678     register_hooks
  679 };