crossroads

Git mirror of https://crossroads.e-tunity.com/
git clone git://git.finwo.net/app/crossroads
Log | Files | Refs | LICENSE

checkdos.cc (4225B)


      1 #include "dispatcher"
      2 
      3 typedef map < long, std::queue<time_t> > AccessMap;
      4 static AccessMap accesslog;
      5 static time_t accesslog_lastclean = 0;
      6 
      7 // Execute an external program upon excess of hard/soft rates
      8 static void run_excess(string const &prog, char const *ip) {
      9     ostringstream o;
     10     o << prog << ' ' << ip;
     11     msg("Max connection rate exceeded, invoking '" << o.str() << '\n');
     12     int ret = sysrun(o.str());
     13     if (ret == -1) {
     14 	throw Error(string("Failed to start system call: ") +
     15 		    strerror(errno));
     16     } else if (ret) {
     17 	warnmsg("Program '" << o.str()  << 
     18 		"' exited with exit status " << ret << '\n');
     19     } else {
     20 	msg("Program '" << o.str() << "' finished.\n");
     21     }
     22 }
     23 
     24 bool Dispatcher::check_dos() {
     25     msg ("Verifying DOS protection\n");
     26     Threadlist::desc("Verifying");
     27 
     28     static int lock;
     29 
     30     // Check 'softmaxconnrate' and 'hardmaxconnrate' now!
     31     // Descend into this block if connrate_time() is set, AND
     32     // either hardmaxconnrate() is set,
     33     // or both softmaxconnrate() and defertime() are set.
     34     if (config.connrate_time() &&
     35 	(config.hardmaxconnrate() ||
     36 	 (config.softmaxconnrate() && config.defertime()))) {
     37 
     38 	// The map lookup/insert key.
     39 	struct sockaddr_in sa = clientfd().clientaddr();
     40 	long key;
     41 	memset(&key, 0, sizeof(key));
     42 	memcpy(&key, &(sa.sin_addr), sizeof(sa.sin_addr));
     43 	       
     44      	time_t now, min_ts;
     45      	now = time(0);
     46      	min_ts = now - config.connrate_time();
     47      	unsigned max_conns = max(config.hardmaxconnrate(),
     48      	  			 config.softmaxconnrate());
     49 
     50 	mutex_lock (&lock);
     51 	accesslog[key].push(now);
     52 	mutex_unlock (&lock);
     53 	
     54 	if (accesslog_lastclean < min_ts) {
     55 	    // Clean the entire access log, it's been a while...
     56 
     57 	    mutex_lock(&lock);
     58 	    accesslog_lastclean = now;
     59 	    mutex_unlock(&lock);
     60 
     61 	    bool done = false;
     62 	    while (!done) {
     63 		done = true;
     64 		for (AccessMap::iterator i = accesslog.begin();
     65 		     i != accesslog.end();
     66 		     i++ ) {
     67 		    if (accesslog[i->first].back() < min_ts) {
     68 			// This IP hasn't made ANY connections in a while
     69 			// -- erase! Also restart loop, i++ won't be valid
     70 			// after erase(i)
     71 			accesslog.erase(i);
     72 			done = false;
     73 			break;
     74 		    } else {
     75 			// Keep popping off this IP's oldest connection
     76 			// until we have only "recent" connections left.
     77 			mutex_lock(&lock);
     78 			while ( accesslog[i->first].front() < min_ts
     79 				|| accesslog[i->first].size() > max_conns )
     80 			    accesslog[i->first].pop();
     81 			mutex_unlock(&lock);
     82 		    }
     83 		}
     84 	    }
     85 	} else {
     86 	    // The "big log" doesn't need to be fully cleaned,
     87 	    // but this particular IP should be!
     88 	    mutex_lock(&lock);
     89 	    while ( (accesslog[key].front() < min_ts)
     90 		    ||
     91 		    (accesslog[key].size() > max_conns)
     92 		)  {
     93 	     	accesslog[key].pop();
     94 	    }
     95 	    mutex_unlock(&lock);
     96 	}
     97 
     98 	if ( config.hardmaxconnrate() &&
     99 	     (accesslog[key].size() >= config.hardmaxconnrate()) ) {
    100 	    // This IP has violated the "HARD" limit!  Reject the connection
    101 	    ostringstream o;
    102 	    o << "Client " << inet2string(clientfd().clientaddr().sin_addr)
    103 	      << " has hit the HARD maximum number of connections ("
    104 	      << config.hardmaxconnrate() << " conections in "
    105 	      << config.connrate_time() << " seconds; "
    106 	      << accesslog[key].size() 
    107 	      << " connections recorded). Client is refused.\n";
    108 	    warnmsg (o.str());
    109 	    run_excess(config.hardmaxconnexcess(),
    110 		       inet2string(clientfd().clientaddr().sin_addr).c_str());
    111 	    return false;
    112 	} else if ( config.softmaxconnrate() &&
    113 		    (accesslog[key].size() >= config.softmaxconnrate()) ) {
    114 	    // This IP has violated the "SOFT" Limit. Go to sleep for a while.
    115 	    ostringstream o;
    116 	    o << "Client " << inet2string(clientfd().clientaddr().sin_addr)
    117 	      << " has hit the SOFT maximum number of connections ("
    118 	      << config.softmaxconnrate() << " connections in "
    119 	      << config.connrate_time() << " sedonds; "
    120 	      << accesslog[key].size()
    121 	      << " connections recorded). Client is deferred for "
    122 	      << config.defertime() << " microseconds.\n";
    123 	    warnmsg (o.str());
    124 	    run_excess(config.softmaxconnexcess(),
    125 		       inet2string(clientfd().clientaddr().sin_addr).c_str());
    126 	    usleep(config.defertime());
    127 	}
    128     }
    129 
    130     return true;
    131 }