⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_evasive20.c

📁 实现DOS攻击的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
mod_evasive for Apache 2
Copyright (c) by Jonathan A. Zdziarski

LICENSE
                                                                                
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
                                                                                
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
                                                                                
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
#include <syslog.h>
#include <errno.h>

#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_request.h"

module AP_MODULE_DECLARE_DATA evasive20_module;

/* BEGIN DoS Evasive Maneuvers Definitions */

#define MAILER	"/bin/mail %s"
#define  LOG( A, ... ) { openlog("mod_evasive", LOG_PID, LOG_DAEMON); syslog( A, __VA_ARGS__ ); closelog(); }

#define DEFAULT_HASH_TBL_SIZE   3097ul  // Default hash table size
#define DEFAULT_PAGE_COUNT      2       // Default maximum page hit count per interval
#define DEFAULT_SITE_COUNT      50      // Default maximum site hit count per interval
#define DEFAULT_PAGE_INTERVAL   1       // Default 1 Second page interval
#define DEFAULT_SITE_INTERVAL   1       // Default 1 Second site interval
#define DEFAULT_BLOCKING_REQUEST		"On"  // Default Block Operation
#define DEFAULT_BLOCKING_PERIOD 10      // Default for Detected IPs; blocked for 10 seconds
#define DEFAULT_LOG_DIR		"/tmp"  // Default temp directory

/* END DoS Evasive Maneuvers Definitions */

/* BEGIN NTT (Named Timestamp Tree) Headers */

enum { ntt_num_primes = 28 };

/* ntt root tree */
struct ntt {
    long size;
    long items;
    struct ntt_node **tbl;
};

/* ntt node (entry in the ntt root tree) */
struct ntt_node {
    char *key;
    time_t timestamp;
    long count;
    struct ntt_node *next;
};

/* ntt cursor */
struct ntt_c {
  long iter_index;
  struct ntt_node *iter_next;
};

struct ntt *ntt_create(long size);
int ntt_destroy(struct ntt *ntt);
struct ntt_node	*ntt_find(struct ntt *ntt, const char *key);
struct ntt_node	*ntt_strstr(struct ntt *ntt, const char *key);
struct ntt_node	*ntt_insert(struct ntt *ntt, const char *key, time_t timestamp);
int ntt_delete(struct ntt *ntt, const char *key);
long ntt_hashcode(struct ntt *ntt, const char *key);	
struct ntt_node *c_ntt_first(struct ntt *ntt, struct ntt_c *c);
struct ntt_node *c_ntt_next(struct ntt *ntt, struct ntt_c *c);

/* END NTT (Named Timestamp Tree) Headers */


/* BEGIN DoS Evasive Maneuvers Globals */

struct ntt *hit_list;	// Our dynamic hash table

static unsigned long hash_table_size = DEFAULT_HASH_TBL_SIZE;
static int page_count = DEFAULT_PAGE_COUNT;
static int page_interval = DEFAULT_PAGE_INTERVAL;
static int site_count = DEFAULT_SITE_COUNT;
static int site_interval = DEFAULT_SITE_INTERVAL;
static int blocking_period = DEFAULT_BLOCKING_PERIOD;

static char *blocking_request = NULL;
static char *email_notify = NULL;
static char *log_dir = NULL;
static char *system_command = NULL;
static const char *whitelist(cmd_parms *cmd, void *dconfig, const char *ip);
static const char *whiteagentlist(cmd_parms *cmd, void *dconfig, const char *agent);
int is_whitelisted(const char *ip);
int is_whiteagentlisted(const char *agent);

/* END DoS Evasive Maneuvers Globals */

static void * create_hit_list(apr_pool_t *p, server_rec *s) 
{
    /* Create a new hit list for this listener */

    hit_list = ntt_create(hash_table_size);
}

static const char *whitelist(cmd_parms *cmd, void *dconfig, const char *ip)
{
  char entry[128];
  snprintf(entry, sizeof(entry), "WHITELIST_%s", ip);
  ntt_insert(hit_list, entry, time(NULL));
  
  return NULL;
}

static const char *whiteagentlist(cmd_parms *cmd, void *dconfig, const char *agent)
{
  char entry[128];
  snprintf(entry, sizeof(entry), "WHITEAGENTLIST_%s", agent);
  ntt_insert(hit_list, entry, time(NULL));
  
  return NULL;
}



static int access_checker(request_rec *r) 
{
    int ret = OK;

    /* BEGIN DoS Evasive Maneuvers Code */

    if (r->prev == NULL && r->main == NULL && hit_list != NULL) {
      char hash_key[2048];
      struct ntt_node *n;
      time_t t = time(NULL);
      char *agent;

      /* Check whitelist */
      if (is_whitelisted(r->connection->remote_ip)) 
        return OK;
        
        
      agent = apr_table_get(r->headers_in, "User-Agent");
      if (agent == NULL) {
          agent = apr_table_get(r->subprocess_env, "User-Agent");
      }
      
      if (is_whiteagentlisted(agent)) 
        return OK;

      /* First see if the IP itself is on "hold" */
      n = ntt_find(hit_list, r->connection->remote_ip);

      if (n != NULL && t-n->timestamp<blocking_period) {
 
        /* If the IP is on "hold", make it wait longer in 403 land */
        ret = HTTP_FORBIDDEN;
        n->timestamp = time(NULL);

      /* Not on hold, check hit stats */
      } else {

        /* Has URI been hit too much? */
        snprintf(hash_key, 2048, "%s_%s", r->connection->remote_ip, r->uri);
        n = ntt_find(hit_list, hash_key);
        if (n != NULL) {

          /* If URI is being hit too much, add to "hold" list and 403 */
          if (t-n->timestamp<page_interval && n->count>=page_count) {
            ret = HTTP_FORBIDDEN;
            ntt_insert(hit_list, r->connection->remote_ip, time(NULL));
          } else {

            /* Reset our hit count list as necessary */
            if (t-n->timestamp>=page_interval) {
              n->count=0;
            }
          }
          n->timestamp = t;
          n->count++;
        } else {
          ntt_insert(hit_list, hash_key, t);
        }

        /* Has site been hit too much? */
        snprintf(hash_key, 2048, "%s_SITE", r->connection->remote_ip);
        n = ntt_find(hit_list, hash_key);
        if (n != NULL) {

          /* If site is being hit too much, add to "hold" list and 403 */
          if (t-n->timestamp<site_interval && n->count>=site_count) {
            ret = HTTP_FORBIDDEN;
            ntt_insert(hit_list, r->connection->remote_ip, time(NULL));
          } else {

            /* Reset our hit count list as necessary */
            if (t-n->timestamp>=site_interval) {
              n->count=0;
            }
          }
          n->timestamp = t;
          n->count++;
        } else {
          ntt_insert(hit_list, hash_key, t);
        }
      }

      /* Perform email notification and system functions */
      if (ret == HTTP_FORBIDDEN) {
        char filename[1024];
        char logfilename[1024];
        struct stat s;
        FILE *file;
        FILE *logfile;
        struct tm *ptr;
        
        
				snprintf(logfilename, sizeof(logfilename), "%s/mod_evasive.log", log_dir != NULL ? log_dir : DEFAULT_LOG_DIR);
        snprintf(filename, sizeof(filename), "%s/dos-%s", log_dir != NULL ? log_dir : DEFAULT_LOG_DIR, r->connection->remote_ip);
        if (stat(filename, &s)) {
          file = fopen(filename, "w");
          logfile = fopen(logfilename, "a");
          if (file != NULL && logfile != NULL) {
            fprintf(file, "%ld\n", getpid());
            fclose(file);
             
            ptr = localtime(&t);
            fprintf(logfile, "'%d-%d-%d %d:%d:%d' %s %ld %d\n", ptr->tm_year+1900, ptr->tm_mon, ptr->tm_mday, ptr->tm_hour, ptr->tm_min, ptr->tm_sec, r->connection->remote_ip, getpid(), DEFAULT_BLOCKING_PERIOD);
            fclose(logfile);

            LOG(LOG_ALERT, "Blacklisting address %s: possible DoS attack.", r->connection->remote_ip);
            if (email_notify != NULL) {
              snprintf(filename, sizeof(filename), MAILER, email_notify);
              file = popen(filename, "w");
              if (file != NULL) {
                fprintf(file, "To: %s\n", email_notify);
                fprintf(file, "Subject: HTTP BLACKLIST %s\n\n", r->connection->remote_ip);
                fprintf(file, "mod_evasive HTTP Blacklisted %s\n", r->connection->remote_ip);
                pclose(file);
              }
            }

            if (system_command != NULL) {
              snprintf(filename, sizeof(filename), system_command, r->connection->remote_ip);
              system(filename);
            }
 
          } else {
            LOG(LOG_ALERT, "Couldn't open logfile %s: %s",filename, strerror(errno));
	  }

        } /* if (temp file does not exist) */

      } /* if (ret == HTTP_FORBIDDEN) */

    } /* if (r->prev == NULL && r->main == NULL && hit_list != NULL) */

    /* END DoS Evasive Maneuvers Code */

    if (ret == HTTP_FORBIDDEN
	&& (ap_satisfies(r) != SATISFY_ANY || !ap_some_auth_required(r))) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
            "client denied by server configuration: %s",
            r->filename);
    }
    
    if (strcasecmp(DEFAULT_BLOCKING_REQUEST, blocking_request) != 0) {      
    	return OK;
    }

    return ret;
}

int is_whitelisted(const char *ip) {
  char hashkey[128];
  char octet[4][4];
  char *dip;
  char *oct;
  int i = 0;

  memset(octet, 0, 16);
  dip = strdup(ip);
  if (dip == NULL)
    return 0;

  oct = strtok(dip, ".");
  while(oct != NULL && i<4) {
    if (strlen(oct)<=3) 
      strcpy(octet[i], oct);
    i++;
    oct = strtok(NULL, ".");
  }
  free(dip);

  /* Exact Match */
  snprintf(hashkey, sizeof(hashkey), "WHITELIST_%s", ip); 
  if (ntt_find(hit_list, hashkey)!=NULL)
    return 1;

  /* IPv4 Wildcards */ 
  snprintf(hashkey, sizeof(hashkey), "WHITELIST_%s.*.*.*", octet[0]);
  if (ntt_find(hit_list, hashkey)!=NULL)
    return 1;

  snprintf(hashkey, sizeof(hashkey), "WHITELIST_%s.%s.*.*", octet[0], octet[1]);
  if (ntt_find(hit_list, hashkey)!=NULL)
    return 1;

  snprintf(hashkey, sizeof(hashkey), "WHITELIST_%s.%s.%s.*", octet[0], octet[1], octet[2]);
  if (ntt_find(hit_list, hashkey)!=NULL)
    return 1;

  /* No match */
  return 0;
}

int is_whiteagentlisted(const char *agent) {
  char hashkey[128];


  /* Exact Match */
  snprintf(hashkey, sizeof(hashkey), "WHITEAGENTLIST_%s", agent); 
  if (ntt_find(hit_list, hashkey)!=NULL)
    return 1;


  /* No match */
  return 0;
}


static apr_status_t destroy_hit_list(void *not_used) {
  ntt_destroy(hit_list);
  free(email_notify);
  free(system_command);
}


/* BEGIN NTT (Named Timestamp Tree) Functions */

static unsigned long ntt_prime_list[ntt_num_primes] = 
{
    53ul,         97ul,         193ul,       389ul,       769ul,
    1543ul,       3079ul,       6151ul,      12289ul,     24593ul,
    49157ul,      98317ul,      196613ul,    393241ul,    786433ul,
    1572869ul,    3145739ul,    6291469ul,   12582917ul,  25165843ul,
    50331653ul,   100663319ul,  201326611ul, 402653189ul, 805306457ul,
    1610612741ul, 3221225473ul, 4294967291ul
};


/* Find the numeric position in the hash table based on key and modulus */

long ntt_hashcode(struct ntt *ntt, const char *key) {
    unsigned long val = 0;
    for (; *key; ++key) val = 5 * val + *key;
    return(val % ntt->size);
}

/* Creates a single node in the tree */

struct ntt_node *ntt_node_create(const char *key) {
    char *node_key;
    struct ntt_node* node;

    node = (struct ntt_node *) malloc(sizeof(struct ntt_node));
    if (node == NULL) {
	return NULL;
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -