Hi, 

    I have just tested and updated the patch,it works ok,and with a little 
performance loss(<1%). The script used looks like this:

        for o3 in `seq 1 254`; do
                for o4 in `seq 1 254`; do
                        host=127.0.$o3.$o4
                        openssl s_client -ssl3 -connect $host:4433 &
                done
                sleep 1
        done

         the server side is like this: openssl s_server

         There is only 1GB memory in my testing machine, so I just tested with 
254/254*2/254*5/254*10 client ip,
if got more client ip, the memory can be eaten up quickly(too many process 
'openssl s_client').

the testing methord I used: 
* compare the time used by the original openssl s_server(not applied the 
patch),  and the applied patch openssl s_server to process
  lots of client's requests.

Hope your response and comment!

Regards,
Guanjun 


>>> On 12/12/2011 at 11:35 AM, in message
<4ee5e6e6020000160000b...@novprvlin0050.provo.novell.com>, "Guan Jun He"
<g...@suse.com> wrote: 
> Hi,
> I have just produced a patch against the upstream HEAD version, 
> to seek a way to fight against DoS attack in openssl itself, 
> the logic is simple, get client's ip address in BIO layer, 
> and send this info to upper SSL layer; In SSL layer, 
> according to the client ip and control policy to do control. 
> And I have just finished the enhancement to use rb-tree as the main struct, 
> the patch is attached,and have took a simple test from 2 machines.
> 
> the test script looks like this:
> 
> #thc-ssl-dosit() { while :; do (while :; do echo R; done) | openssl s_client 
> -ssl3 -connect hostname:4433 2>/dev/null; done }
> thc-ssl-dosit() { openssl s_client -ssl3 -connect hostname:4433 2>/dev/null;}
> for x in `seq 1 5000`; do thc-ssl-dosit & done
> 
> and looks like it works ok,and perform very well.
> 
> But, still, I can not give real pressure to the rb-tree, actually only 2 
> different ip address used,
> and 'openssl s_client' have no option to use a bonding ip address, so, still 
> have no environment
> to make a real pressure test.Do you have any method to do this?If someone 
> think add a bonding ip address
>  option is a good idea, please response.
> 
> The struct has been changed to use rb-tree, so, the performance can be 
> estimated.
> 
> Please response and comment!
> 
> thanks,
> Guanjun


diff -Nupr openssl/ssl/s3_srvr.c openssl.1/ssl/s3_srvr.c
--- openssl/ssl/s3_srvr.c       2011-09-05 21:36:22.000000000 +0800
+++ openssl.1/ssl/s3_srvr.c     2011-12-19 16:56:10.000000000 +0800
@@ -169,6 +169,497 @@
 #include <openssl/krb5_asn.h>
 #endif
 #include <openssl/md5.h>
+#include <time.h>
+
+static time_t start = 0;
+static int timer_interval = 300;/*5 min, these 2 values are configure-able*/
+static int dos_benchmark = 3000;
+
+typedef enum color_t
+{
+       RED = 0,
+       BLACK = 1
+}color_t;
+
+typedef struct rb_node_t
+{
+       struct rb_node_t *left, *right, *parent;
+       struct rb_node_t *next;/*also keep a simple list, for destroy a tree*/
+       unsigned long key;/*ip*/
+       unsigned long data;/*counter*/
+       color_t color;
+}rb_node_t;
+
+static rb_node_t* rb_dlist = NULL;
+static rb_node_t* rb_iter = NULL;
+static rb_node_t maxCounterNode;
+static rb_node_t* clist = NULL;
+static rb_node_t* blacklist = NULL;
+
+rb_node_t* rb_insert(unsigned long key, unsigned long data, rb_node_t* root);
+rb_node_t* rb_insert2(rb_node_t* node, rb_node_t* root);
+
+rb_node_t* rb_search(unsigned long key, rb_node_t* root);
+/*rb_node_t* rb_search(rb_node_t* node, rb_node_t* root);*/
+
+rb_node_t* rb_erase(unsigned long key, rb_node_t* root);
+/*rb_node_t* rb_erase(rb_node_t* node, rb_node_t* root);*/
+
+void rb_destroy(rb_node_t* root);
+
+void rb_destroy(rb_node_t* root)
+{
+       rb_node_t* tmp_node = NULL;
+       while(root)
+       {
+               tmp_node = root->next;
+               free(root);
+               root = tmp_node;
+       }
+}
+
+static rb_node_t* rb_new_node(unsigned long key, unsigned long data)
+{
+       rb_node_t *node = (rb_node_t*)malloc(sizeof(struct rb_node_t));
+       if (!node)
+       {
+               return NULL;
+       }
+       node->key = key;
+               node->data = data;
+       return node;
+}
+
+static rb_node_t* rb_rotate_left(rb_node_t* node, rb_node_t* root)
+{
+       rb_node_t* right = node->right;
+       if ((node->right = right->left))
+       {
+               right->left->parent = node;
+       }
+       right->left = node;
+
+       if ((right->parent = node->parent))
+       {
+               if (node == node->parent->right)
+               {
+                       node->parent->right = right;
+               }
+               else
+               {
+                       node->parent->left = right;
+               }
+       }
+       else
+       {
+               root = right;
+       }
+       node->parent = right;
+
+       return root;
+}
+
+static rb_node_t* rb_rotate_right(rb_node_t* node, rb_node_t* root)
+{
+       rb_node_t* left = node->left;
+
+       if ((node->left = left->right))
+       {
+               left->right->parent = node;
+       }
+       left->right = node;
+
+       if ((left->parent = node->parent))
+       {
+               if (node == node->parent->right)
+               {
+                       node->parent->right = left;
+               }
+               else
+               {
+                       node->parent->left = left;
+               }
+       }
+       else
+       {
+               root = left;
+       }
+       node->parent = left;
+
+       return root;
+}
+
+static rb_node_t* rb_insert_rebalance(rb_node_t *node, rb_node_t *root)
+{
+       rb_node_t *parent, *gparent, *uncle, *tmp;
+
+       while ((parent = node->parent) && parent->color == RED)
+       {
+               gparent = parent->parent;
+               if (parent == gparent->left)
+               {
+                       uncle = gparent->right;
+                       if (uncle && uncle->color == RED)
+                       {
+                               uncle->color = BLACK;
+                               parent->color = BLACK;
+                               gparent->color = RED;
+                               node = gparent;
+                       }
+                       else
+                       {
+                               if (parent->right == node)
+                               {
+                                       root = rb_rotate_left(parent, root);
+                                       tmp = parent;
+                                       parent = node;
+                                       node = tmp;
+                               }
+                               parent->color = BLACK;
+                               gparent->color = RED;
+                               root = rb_rotate_right(gparent, root);
+                       }
+               }
+               else
+               {
+                       uncle = gparent->left;
+                       if (uncle && uncle->color == RED)
+                       {
+                               uncle->color = BLACK;
+                               parent->color = BLACK;
+                               gparent->color = RED;
+                               node = gparent;
+                       }
+                       else
+                       {
+                               if (parent->left == node)
+                               {
+                                       root = rb_rotate_right(parent, root);
+                                       tmp = parent;
+                                       parent = node;
+                                       node = tmp;
+                               }
+                               parent->color = BLACK;
+                               gparent->color = RED;
+                               root = rb_rotate_left(gparent, root);
+                       }
+               }
+       }
+       root->color = BLACK;
+
+       return root;
+}
+
+static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, 
rb_node_t *root)
+{
+       rb_node_t *other, *o_left, *o_right;
+
+       while ((!node || node->color == BLACK) && node != root)
+       {
+               if (parent->left == node)
+               {
+                       other = parent->right;
+                       if (other->color == RED)
+                       {
+                               other->color = BLACK;
+                               parent->color = RED;
+                               root = rb_rotate_left(parent, root);
+                               other = parent->right;
+                       }
+                       if ((!other->left || other->left->color == BLACK) &&
+                                       (!other->right || other->right->color 
== BLACK))
+                       {
+                               other->color = RED;
+                               node = parent;
+                               parent = node->parent;
+                       }
+                       else
+                       {
+                               if (!other->right || other->right->color == 
BLACK)
+                               {
+                                       if ((o_left = other->left))
+                                       {
+                                               o_left->color = BLACK;
+                                       }
+                                       other->color = RED;
+                                       root = rb_rotate_right(other, root);
+                                       other = parent->right;
+                               }
+                               other->color = parent->color;
+                               parent->color = BLACK;
+                               if (other->right)
+                               {
+                                       other->right->color = BLACK;
+                               }
+                               root = rb_rotate_left(parent, root);
+                               node = root;
+                               break;
+                       }
+               }
+               else
+               {
+                       other = parent->left;
+                       if (other->color == RED)
+                       {
+                               other->color = BLACK;
+                               parent->color = RED;
+                               root = rb_rotate_right(parent, root);
+                               other = parent->left;
+                       }
+
+                       if ((!other->left || other->left->color == BLACK) &&
+                                       (!other->right || other->right->color 
== BLACK))
+                       {
+                               other->color = RED;
+                               node = parent;
+                               parent = node->parent;
+                       }
+                       else
+                       {
+                               if (!other->left || other->left->color == BLACK)
+                               {
+                                       if ((o_right = other->right))
+                                       {
+                                               o_right->color = BLACK;
+                                       }
+                                       other->color = RED;
+                                       root = rb_rotate_left(other, root);
+                                       other = parent->left;
+                               }
+                               other->color = parent->color;
+                               parent->color = BLACK;
+                               if (other->left)
+                               {
+                                       other->left->color = BLACK;
+                               }
+                               root = rb_rotate_right(parent, root);
+                               node = root;
+                               break;
+                       }
+               }
+       }
+       if (node)
+       {
+               node->color = BLACK;
+       }
+
+       return root;
+}
+
+static rb_node_t* rb_search_ass(unsigned long key, rb_node_t* root, 
rb_node_t** save)
+{
+       rb_node_t *node = root, *parent = NULL;
+
+       while (node)
+       {
+               parent = node;
+               if (node->key > key)
+               {
+                       node = node->left;
+               }
+               else if (node->key < key)
+               {
+                       node = node->right;
+               }
+               else
+               {
+                       return node;
+               }
+       }
+
+       if (save)
+       {
+               *save = parent;
+       }
+
+       return NULL;
+}
+
+rb_node_t* rb_search(unsigned long key, rb_node_t* root)
+{
+       return rb_search_ass(key, root, NULL);
+}
+
+rb_node_t* rb_insert(unsigned long key, unsigned long data, rb_node_t* root)
+{
+       rb_node_t *parent = NULL, *node;
+       parent = NULL;
+
+       if ((node = rb_search_ass(key, root, &parent)))
+       {
+               return root;
+       }
+
+       node = rb_new_node(key, data);
+       node->parent = parent;
+       node->left = node->right = NULL;
+       node->color = RED;
+
+       if (parent)
+       {
+               if (parent->key > key)
+               {
+                       parent->left = node;
+               }
+               else
+               {
+                       parent->right = node;
+               }
+       }
+       else
+       {
+               root = node;
+       }
+
+       return rb_insert_rebalance(node, root);
+}
+
+rb_node_t* rb_insert2(rb_node_t* ins_node, rb_node_t* root)
+{
+       rb_node_t *parent = NULL, *node;
+       parent = NULL;
+
+       if (node = rb_search_ass(ins_node->key, root, &parent))
+       {
+               return root;
+       }
+
+       node = ins_node;
+       node->parent = parent;
+       node->left = node->right = NULL;
+       node->color = RED;
+
+       if (parent)
+       {
+               if (parent->key > node->key)
+               {
+                       parent->left = node;
+               }
+               else
+               {
+                       parent->right = node;
+               }
+       }
+       else
+       {
+               root = node;
+       }
+
+       return rb_insert_rebalance(node, root);
+}
+
+rb_node_t* rb_erase(unsigned long key, rb_node_t *root)
+{
+       rb_node_t *child, *parent, *old, *left, *node;
+       color_t color;
+
+       if (!(node = rb_search_ass(key, root, NULL)))
+       {
+               return root;
+       }
+       old = node;
+       if (node->left && node->right)
+       {
+               node = node->right;
+               while ((left = node->left) != NULL)
+               {
+                       node = left;
+               }
+               child = node->right;
+               parent = node->parent;
+               color = node->color;
+
+               if (child)
+               {
+                       child->parent = parent;
+               }
+               if (parent)
+               {
+                       if (parent->left == node)
+                       {
+                               parent->left = child;
+                       }
+                       else
+                       {
+                               parent->right = child;
+                       }
+               }
+               else
+               {
+                       root = child;
+               }
+               if (node->parent == old)
+               {
+                       parent = node;
+               }
+               node->parent = old->parent;
+               node->color = old->color;
+               node->right = old->right;
+               node->left = old->left;
+               if (old->parent)
+               {
+                       if (old->parent->left == old)
+                       {
+                               old->parent->left = node;
+                       }
+                       else
+                       {
+                               old->parent->right = node;
+                       }
+               }
+               else
+               {
+                       root = node;
+               }
+
+               old->left->parent = node;
+               if (old->right)
+               {
+                       old->right->parent = node;
+               }
+       }
+       else
+       {
+               if (!node->left)
+               {
+                       child = node->right;
+               }
+               else if (!node->right)
+               {
+                       child = node->left;
+               }
+               parent = node->parent;
+               color = node->color;
+               if (child)
+               {
+                       child->parent = parent;
+               }
+               if (parent)
+               {
+                       if (parent->left == node)
+                       {
+                               parent->left = child;
+                       }
+                       else
+                       {
+                               parent->right = child;
+                       }
+               }
+               else
+               {
+                       root = child;
+               }
+       }
+       free(old);
+       if (color == BLACK)
+       {
+               root = rb_erase_rebalance(child, parent, root);
+       }
+       return root;
+}
+
+
+
 
 static const SSL_METHOD *ssl3_get_server_method(int ver);
 
@@ -220,6 +711,10 @@ int ssl3_accept(SSL *s)
 #ifndef OPENSSL_NO_SRP
        int srp_no_username =0;
 #endif
+       time_t current = 0;
+       int duration = 0;
+       int tmp_dos = 0;
+       rb_node_t* tmp_node = NULL;
 
        RAND_add(&Time,sizeof(Time),0);
        ERR_clear_error();
@@ -343,6 +838,91 @@ int ssl3_accept(SSL *s)
 #ifndef OPENSSL_NO_SRP
                case SSL3_ST_SR_CLNT_HELLO_SRP_USERNAME:
 #endif
+                       if(s->client && !getenv("OPENSSL_NO_DOS_CONTROL"))
+                       {
+                               CRYPTO_r_lock(CRYPTO_LOCK_SSL);
+                               if(blacklist != NULL)
+                               {
+                                       if(tmp_node=rb_search(s->client, 
blacklist))
+                                       {
+                                               current = time(NULL);
+                                               duration = (int)(current - 
tmp_node->data);
+                                               if(duration > 60 * 30)/*30 min, 
clear the blacklist*/
+                                               {
+                                                       
CRYPTO_r_unlock(CRYPTO_LOCK_SSL);
+                                                       
CRYPTO_w_lock(CRYPTO_LOCK_SSL);
+                                                       blacklist = 
rb_erase(tmp_node->key, blacklist);
+                                                       
CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
+                                                       
CRYPTO_r_lock(CRYPTO_LOCK_SSL);
+                                                       goto dos_normal;
+                                               }
+                                               
CRYPTO_r_unlock(CRYPTO_LOCK_SSL);
+                                               goto end;
+                                       }
+                               }
+dos_normal:
+                               if(clist != NULL)
+                               {
+                                       current = time(NULL);
+                                       duration = (int)(current - start);
+                                       tmp_node = rb_search(s->client, clist);
+                                       CRYPTO_r_unlock(CRYPTO_LOCK_SSL);
+                                       CRYPTO_w_lock(CRYPTO_LOCK_SSL);
+                                       if(getenv("OPENSSL_DOS_TIMER_INTERVAL") 
!= NULL)
+                                       {
+                                               tmp_dos = 
atoi(getenv("OPENSSL_DOS_TIMER_INTERVAL"));
+                                               timer_interval = 
tmp_dos?tmp_dos:timer_interval;
+                                       }
+                                       if(getenv("OPENSSL_DOS_BENCHAMARK") != 
NULL)
+                                       {
+                                               tmp_dos = 
atoi(getenv("OPENSSL_DOS_BENCHAMARK"));
+                                               dos_benchmark = 
tmp_dos?tmp_dos:dos_benchmark;
+                                       }
+                                       if(tmp_node != NULL)
+                                       {
+                                               tmp_node->data++;
+                                               if(tmp_node->data > 
maxCounterNode.data)
+                                               {
+                                                       maxCounterNode.data = 
tmp_node->data;
+                                                       maxCounterNode.key = 
tmp_node->key;
+                                               }
+                                               /*do the policy and clear the 
statistics data*/
+                                               if(duration > timer_interval)
+                                               {
+                                                       if(maxCounterNode.data 
> dos_benchmark)
+                                                       {
+                                                               
maxCounterNode.data = time(NULL);/*time stamp*/ 
+                                                               blacklist = 
rb_insert(maxCounterNode.key, maxCounterNode.data, blacklist);
+                                                       }
+                                                       maxCounterNode.data = 0;
+                                                       rb_destroy(rb_dlist);
+                                                       clist = NULL;
+                                                       start = time(NULL);
+                                               }
+                                       }
+                                       else
+                                       {
+                                               tmp_node = 
rb_new_node(s->client, 1);
+                                               clist = rb_insert2(tmp_node, 
clist);
+                                               tmp_node->next = NULL;
+                                               rb_iter->next = tmp_node;
+                                               rb_iter = tmp_node;
+                                       }
+                                       CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
+                               }
+                               else/*initialize the tree*/
+                               {
+                                       CRYPTO_r_unlock(CRYPTO_LOCK_SSL);
+                                       CRYPTO_w_lock(CRYPTO_LOCK_SSL);
+                                       clist = rb_insert(s->client, 1, clist);
+                                       clist->next = NULL;
+                                       rb_dlist = rb_iter = clist;
+                                       maxCounterNode.key = clist->key;
+                                       maxCounterNode.data = 1;
+                                       start = time(NULL);
+                                       CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
+                               }
+                       }
 
                        s->shutdown=0;
                        ret=ssl3_get_client_hello(s);
diff -Nupr openssl/ssl/ssl.h openssl.1/ssl/ssl.h
--- openssl/ssl/ssl.h   2011-11-16 07:50:52.000000000 +0800
+++ openssl.1/ssl/ssl.h 2011-12-09 12:21:12.000000000 +0800
@@ -1347,6 +1347,7 @@ struct ssl_st
 #else
 #define session_ctx ctx
 #endif /* OPENSSL_NO_TLSEXT */
+       unsigned long client;
        };
 
 #endif
diff -Nupr openssl/ssl/ssl_lib.c openssl.1/ssl/ssl_lib.c
--- openssl/ssl/ssl_lib.c       2011-11-16 07:50:52.000000000 +0800
+++ openssl.1/ssl/ssl_lib.c     2011-12-09 12:20:49.000000000 +0800
@@ -161,6 +161,11 @@
 #include <openssl/engine.h>
 #endif
 
+#include<sys/socket.h>
+#include<sys/types.h>
+#include<netinet/in.h>
+
+
 const char *SSL_version_str=OPENSSL_VERSION_TEXT;
 
 SSL3_ENC_METHOD ssl3_undef_enc_method={
@@ -607,6 +612,8 @@ void SSL_free(SSL *s)
 
 void SSL_set_bio(SSL *s,BIO *rbio,BIO *wbio)
        {
+        struct sockaddr_in c_addr;
+        socklen_t len;
        /* If the output buffering BIO is still in place, remove it
         */
        if (s->bbio != NULL)
@@ -623,6 +630,13 @@ void SSL_set_bio(SSL *s,BIO *rbio,BIO *w
                BIO_free_all(s->wbio);
        s->rbio=rbio;
        s->wbio=wbio;
+       /*add the ip to SSL*/
+       if(s && s->rbio && s->rbio->method->type == BIO_TYPE_SOCKET)
+       {
+               len = sizeof c_addr;
+               getpeername(s->rbio->num, (struct sockaddr*)&c_addr, &len);
+               s->client = ntohl(c_addr.sin_addr.s_addr);
+       }
        }
 
 BIO *SSL_get_rbio(const SSL *s)

Reply via email to