unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

tls_antidos.c (2811B)

      1 /*
      2  * TLS Anti DoS module
      3  * This protects against TLS renegotiation attacks while still allowing us
      4  * to leave renegotiation on with all it's security benefits.
      5  *
      6  * (C) Copyright 2015- Bram Matthys and the UnrealIRCd team.
      7  * 
      8  * License: GPLv2 or later
      9  */
     10 
     11 #include "unrealircd.h"
     12 
     13 ModuleHeader MOD_HEADER
     14   = {
     15 	"tls_antidos",
     16 	"5.0",
     17 	"TLS Renegotiation DoS protection",
     18 	"UnrealIRCd Team",
     19 	"unrealircd-6",
     20     };
     21 
     22 #define HANDSHAKE_LIMIT_COUNT 3
     23 #define HANDSHAKE_LIMIT_SECS 300
     24 
     25 typedef struct SAD SAD;
     26 struct SAD {
     27 	Client *client; /**< client */
     28 	time_t ts; /**< time */
     29 	int n; /**< number of times */
     30 };
     31 
     32 int tls_antidos_index = 0; /* slot# we acquire from OpenSSL. Hmm.. looks awfully similar to our moddata system ;) */
     33 
     34 /* Forward declaration */
     35 int tls_antidos_handshake(Client *client);
     36 
     37 void tls_antidos_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp);
     38 
     39 MOD_INIT()
     40 {
     41 	HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, tls_antidos_handshake);
     42 
     43 	MARK_AS_OFFICIAL_MODULE(modinfo);
     44 	
     45 	ModuleSetOptions(modinfo->handle, MOD_OPT_PERM, 1);
     46 	/* Note that we cannot be MOD_OPT_PERM_RELOADABLE as we use OpenSSL functions to register
     47 	 * an index and callback function.
     48 	 */
     49 	
     50 	tls_antidos_index = SSL_get_ex_new_index(0, "tls_antidos", NULL, NULL, tls_antidos_free);
     51 	
     52 	return MOD_SUCCESS;
     53 }
     54 
     55 MOD_LOAD()
     56 {
     57 	return MOD_SUCCESS;
     58 }
     59 
     60 MOD_UNLOAD()
     61 {
     62 	return MOD_SUCCESS;
     63 }
     64 
     65 /** Called upon handshake (and other events) */
     66 void ssl_info_callback(const SSL *ssl, int where, int ret)
     67 {
     68 	if (where & SSL_CB_HANDSHAKE_START)
     69 	{
     70 		SAD *e = SSL_get_ex_data(ssl, tls_antidos_index);
     71 		Client *client = e->client;
     72 		
     73 		if (IsServer(client) || IsDeadSocket(client))
     74 			return; /* if it's a server, or already pending to be killed off then we don't care */
     75 
     76 		if (e->ts < TStime() - HANDSHAKE_LIMIT_SECS)
     77 		{
     78 			e->ts = TStime();
     79 			e->n = 1;
     80 		} else {
     81 			e->n++;
     82 			if (e->n >= HANDSHAKE_LIMIT_COUNT)
     83 			{
     84 				unreal_log(ULOG_INFO, "flood", "TLS_HANDSHAKE_FLOOD", client, "TLS Handshake flood detected from $client.details -- killed");
     85 				dead_socket(client, "TLS Handshake flood detected");
     86 			}
     87 		}
     88 	}
     89 }
     90 
     91 /** Called when a client has just connected to us.
     92  * This function is called quite quickly after accept(),
     93  * in any case very likely before any data has been received.
     94  */
     95 int tls_antidos_handshake(Client *client)
     96 {
     97 	if (client->local->ssl)
     98 	{
     99 		SAD *sad = safe_alloc(sizeof(SAD));
    100 		sad->client = client;
    101 		SSL_set_info_callback(client->local->ssl, ssl_info_callback);
    102 		SSL_set_ex_data(client->local->ssl, tls_antidos_index, sad);
    103 	}
    104 	return 0;
    105 }
    106 
    107 /** Called by OpenSSL when the SSL * structure is freed (so we can free up our custom struct too) */
    108 void tls_antidos_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp)
    109 {
    110 	safe_free(ptr);
    111 }