*** mod_dosdetector.c	2013-10-27 01:49:56.000000000 +0900
--- mod_dosdetector.fork.c	2013-12-05 14:29:34.000000000 +0900
***************
*** 29,34 ****
--- 29,37 ----
  //#include <netinet/in.h>
  #include <time.h>
  #include <regex.h>
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <string.h>
  #include "httpd.h"
  #include "http_config.h"
  #include "http_request.h"
***************
*** 88,93 ****
--- 91,102 ----
  } client_list_t;
  
  typedef struct {
+ 	struct in_addr ip;
+ 	struct in_addr mask;
+ 	char *ip_char;
+ } ip_range_t;
+ 
+ typedef struct {
  	signed int detection;
      signed int threshold;
      signed int ban_threshold;
***************
*** 96,101 ****
--- 105,113 ----
  	signed int forwarded;
      apr_array_header_t *ignore_contenttype;
      apr_array_header_t *contenttype_regexp;
+     apr_array_header_t *ignore_ip_range;
+     apr_array_header_t *include_path;
+     apr_array_header_t *exclude_path;
  } dosdetector_dir_config;
  
  static long table_size  = DEFAULT_TABLE_SIZE;
***************
*** 146,152 ****
  	size =  sizeof(client_list_t) + table_size * sizeof(client_t);
  
      ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
! 				 "Create or Joining shmem. name: %s, size: %zd", shmname, size);
      if(lock) apr_global_mutex_lock(lock);
      apr_status_t rc = apr_shm_attach(&shm, shmname, p);
      if (APR_SUCCESS != rc) {
--- 158,164 ----
  	size =  sizeof(client_list_t) + table_size * sizeof(client_t);
  
      ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
! 				 "Create or Joining shmem. name: %s, size: %d", shmname, size);
      if(lock) apr_global_mutex_lock(lock);
      apr_status_t rc = apr_shm_attach(&shm, shmname, p);
      if (APR_SUCCESS != rc) {
***************
*** 232,237 ****
--- 244,252 ----
  	cfg->forwarded  = 0;
      cfg->ignore_contenttype = apr_array_make(p, 0, sizeof(char *));
      cfg->contenttype_regexp = apr_array_make(p, 0, sizeof(char *));
+     cfg->ignore_ip_range = apr_array_make(p, 0, sizeof(ip_range_t *));
+     cfg->include_path = apr_array_make(p, 0, sizeof(char *));
+     cfg->exclude_path = apr_array_make(p, 0, sizeof(char *));
  
      return (void *) cfg;
  }
***************
*** 247,252 ****
--- 262,292 ----
  	return;
  }
  
+ static int dosdetector_check_naddr(struct in_addr *ip_target, apr_array_header_t *ignore_ip_range)
+ {
+ 
+ 	int i;
+ 	for (i = 0; i < ignore_ip_range->nelts; i++) {
+ 		ip_range_t *ip_range = ((ip_range_t **) ignore_ip_range->elts)[i];
+ 		if((ip_range->ip.s_addr & ip_range->mask.s_addr) == (ip_target->s_addr & ip_range->mask.s_addr)){
+ 			DEBUGLOG("dosdetector: check_naddr: %s", ip_range->ip_char);
+ 			return 2;
+ 		}
+ 	}
+ 
+ 	return 0;
+ }
+ 
+ static int dosdetector_check_addr(const char *ip, apr_array_header_t *ignore_ip_range)
+ {
+ 	struct in_addr ip_target;
+ 	if (inet_aton(ip, &ip_target) == 0) {
+ 		DEBUGLOG("dosdetector: check_addr: %s", ip);
+ 		return 1;
+ 	}
+ 	return dosdetector_check_naddr(&ip_target, ignore_ip_range);
+ }
+ 
  static int dosdetector_handler(request_rec *r)
  {
  	//DEBUGLOG("dosdetector_handler is called");
***************
*** 257,267 ****
      if (!ap_is_initial_req(r)) return DECLINED;
  
      //char **ignore_contenttype = (char **) cfg->ignore_contenttype->elts;
! 	
      const char *content_type;
      const char *address_tmp;
      const char *address = NULL;
      int i;
  
      content_type = ap_sub_req_lookup_uri(r->uri, r, NULL)->content_type;
      if (!content_type) {
--- 297,326 ----
      if (!ap_is_initial_req(r)) return DECLINED;
  
      //char **ignore_contenttype = (char **) cfg->ignore_contenttype->elts;
! 
      const char *content_type;
      const char *address_tmp;
      const char *address = NULL;
      int i;
+ 	
+     for (i = 0; i < cfg->exclude_path->nelts; i++) {
+         char *path = ((char **) cfg->exclude_path->elts)[i];
+         if(strncmp(path, r->uri, strlen(path)) == 0){
+             return DECLINED;
+         }
+     }
+     if(cfg->include_path->nelts > 0) {
+         int matches = 0;
+         for (i = 0; i < cfg->include_path->nelts; i++) {
+             char *path = ((char **) cfg->include_path->elts)[i];
+             if(strncmp(path, r->uri, strlen(path)) == 0){
+                 matches++;
+             }
+         }
+         if (matches <= 0) {
+             return DECLINED;
+         }
+     }
  
      content_type = ap_sub_req_lookup_uri(r->uri, r, NULL)->content_type;
      if (!content_type) {
***************
*** 274,283 ****
  
  	if (cfg->forwarded){
  		if ((address_tmp = apr_table_get(r->headers_in, "X-Forwarded-For")) != NULL){
! 			const char *i = address_tmp;
! 			while(*i != 0 && *i != ',')
! 				i++;
! 			address = apr_pstrndup(r->pool, address_tmp, i - address_tmp);
  		}
  	}
  	if (address == NULL) {
--- 333,360 ----
  
  	if (cfg->forwarded){
  		if ((address_tmp = apr_table_get(r->headers_in, "X-Forwarded-For")) != NULL){
! 			DEBUGLOG("dosdetector: x-forwarded-for: \"%s\"", address_tmp);
! 			const char *tmp = address_tmp;
! 			char *token;
! 			apr_array_header_t *ip_array = apr_array_make(r->pool, 0, sizeof(char*));
! 			while ((token = ap_get_token(r->pool, &tmp, 1)) && *token) {
! 				DEBUGLOG("dosdetector:   token: \"%s\"", token);
! 				if (dosdetector_check_addr(token, cfg->ignore_ip_range) == 0) {
! 					DEBUGLOG("dosdetector:     -> ok: \"%s\"", token);
! 					*(char **) apr_array_push(ip_array) = token;
! 				}
! 				if (*tmp != '\0') {
! 					tmp++;
! 				}
! 			}
! 			if (ip_array->nelts <= 0) {
! 				return DECLINED;
! 			}
! 			address = ((char **) ip_array->elts)[(ip_array->nelts) - 1];
! 			//address = ((char **) ip_array->elts)[0];
! 		}
! 		else {
! 			return DECLINED;
  		}
  	}
  	if (address == NULL) {
***************
*** 312,317 ****
--- 389,398 ----
  			return DECLINED;
  		}
  	}
+ 	if(dosdetector_check_naddr(&addr, cfg->ignore_ip_range)) {
+ 		TRACELOG("dosdetector: '%s' is  a ignoring IP addresss", address);
+ 		return DECLINED;
+ 	}
  	if (lock) apr_global_mutex_lock(lock);
  	client_t *client = get_client(client_list, addr, cfg->period);
  	if (lock) apr_global_mutex_unlock(lock);
***************
*** 451,456 ****
--- 532,607 ----
      return NULL;
  }
  
+ static const char *set_ignore_ip_range_config(cmd_parms *parms, void *mconfig,
+ 					 const char *arg)
+ {
+     dosdetector_dir_config *cfg = (dosdetector_dir_config *) mconfig;
+     char *s;
+     char ip[strlen(arg) + 1];
+     strcpy(ip, arg);
+ 
+     ip_range_t *ip_range = (ip_range_t *) apr_pcalloc(parms->pool, sizeof (ip_range_t));
+ 
+     if ((s = ap_strchr(ip, '/'))) {
+         *s++ = '\0';
+         if(inet_aton(ip, &ip_range->ip) == 0) {
+             /* looked nothing like an IP address */
+             return "An IP address was expected";
+         }
+         if(strlen(s) <= 2) {
+             int mask_length;
+             if((mask_length = atoi(s)) != 0 && mask_length > 0 && mask_length <= 32) {
+                 uint32_t mask = UINT32_C(0xffffffff) << (32 - mask_length);
+                 char mask_char[sizeof("255.255.255.255")];
+                 sprintf(mask_char, "%d.%d.%d.%d", (mask >> (8 * 3)) & UINT32_C(0x000000ff), (mask >> (8 * 2)) & UINT32_C(0x000000ff),
+                     (mask >> (8 * 1)) & UINT32_C(0x000000ff), (mask >> (8 * 0)) & UINT32_C(0x000000ff));
+                 if(inet_aton(mask_char, &ip_range->mask) == 0) {
+                     return "An IP address was expected";
+                 }
+             }
+             else {
+                 /* looked nothing like an IP address */
+                 return "An IP address was expected";
+             }
+         }
+         else if(inet_aton(s, &ip_range->mask) == 0) {
+             /* looked nothing like an IP address */
+             return "An IP address was expected";
+         }
+     }
+     else if (inet_aton(ip, &ip_range->ip)) {
+         if(inet_aton("255.255.255.255", &ip_range->mask) == 0) {
+             /* looked nothing like an IP address */
+             return "An IP address was expected";
+ 	}
+     }
+     else {
+         /* looked nothing like an IP address */
+         return "An IP address was expected";
+     }
+ 
+     ip_range->ip_char = apr_pstrdup(parms->pool, arg);
+     *(ip_range_t **) apr_array_push(cfg->ignore_ip_range) = ip_range;
+ 
+     return NULL;
+ }
+ 
+ static const char *set_include_path_config(cmd_parms *parms, void *mconfig,
+ 					 const char *arg)
+ {
+     dosdetector_dir_config *cfg = (dosdetector_dir_config *) mconfig;
+     *(char **) apr_array_push(cfg->include_path) = apr_pstrdup(parms->pool, arg);
+     return NULL;
+ }
+ 
+ static const char *set_exclude_path_config(cmd_parms *parms, void *mconfig,
+ 					 const char *arg)
+ {
+     dosdetector_dir_config *cfg = (dosdetector_dir_config *) mconfig;
+     *(char **) apr_array_push(cfg->exclude_path) = apr_pstrdup(parms->pool, arg);
+     return NULL;
+ }
+ 
  static command_rec dosdetector_cmds[] = {
      AP_INIT_TAKE1("DoSDetection", set_detection_config, NULL, OR_FILEINFO,
       "Enable to detect DoS Attack or not"),
***************
*** 470,475 ****
--- 621,632 ----
       "Use X-Forwarded-For header for Remote Address"),
      AP_INIT_ITERATE("DoSIgnoreContentType", set_ignore_contenttype_config, NULL, OR_FILEINFO,
       "The names of ignoring Content Type"),
+     AP_INIT_ITERATE("DoSIgnoreIpRange", set_ignore_ip_range_config, NULL, OR_FILEINFO,
+      "IPs of ignoring"),
+     AP_INIT_ITERATE("DoSIncludePath", set_include_path_config, NULL, OR_FILEINFO,
+      "Path of Include"),
+     AP_INIT_ITERATE("DoSExcludePath", set_exclude_path_config, NULL, OR_FILEINFO,
+      "Path of Exclude"),
      {NULL},
  };
  
