完成ssl session cache部分的编写。
This commit is contained in:
299
platform/src/ssl_sess_cache.cpp
Normal file
299
platform/src/ssl_sess_cache.cpp
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <ssl_sess_cache.h>
|
||||||
|
#include <ssl.h>
|
||||||
|
#include <MESA_htable.h>
|
||||||
|
#include <field_stat2.h>
|
||||||
|
|
||||||
|
#define SESS_CACHE_NOT_FOUND -1
|
||||||
|
#define SESS_CACHE_FOUND 0
|
||||||
|
#define SESS_CACHE_UPDATE_OLD 1
|
||||||
|
#define SESS_CACHE_ADD_NEW 2
|
||||||
|
#define SESS_CACHE_INVALID 3
|
||||||
|
|
||||||
|
struct asn1_sess
|
||||||
|
{
|
||||||
|
unsigned char* buff;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
struct sess_set_args
|
||||||
|
{
|
||||||
|
MESA_htable_handle hash;
|
||||||
|
struct asn1_sess* new_sess;
|
||||||
|
};
|
||||||
|
struct sess_cache
|
||||||
|
{
|
||||||
|
enum tfe_conn_dir served_for;
|
||||||
|
MESA_htable_handle hash;
|
||||||
|
long long hit_cnt, miss_cnt,del_err;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ssl_sess_free_serialized(void *data)
|
||||||
|
{
|
||||||
|
struct asn1_sess* p=(struct asn1_sess*)data;
|
||||||
|
free(p->buff);
|
||||||
|
p->size=0;
|
||||||
|
free(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static struct asn1_sess* ssl_sess_serialize(SSL_SESSION *sess)
|
||||||
|
{
|
||||||
|
struct asn1_sess* result=ALLOC(struct asn1_sess,1);
|
||||||
|
result->size = i2d_SSL_SESSION(sess, NULL);
|
||||||
|
/*When using i2d_SSL_SESSION(), the memory location pointed to by pp must be large enough to hold the binary representation of the session.
|
||||||
|
There is no known limit on the size of the created ASN1 representation, so the necessary amount of space should be obtained by first calling
|
||||||
|
i2d_SSL_SESSION() with pp=NULL, and obtain the size needed, then allocate the memory and call i2d_SSL_SESSION() again.*/
|
||||||
|
result->buff=ALLOC(unsigned char,result->size);
|
||||||
|
i2d_SSL_SESSION(sess, &(result->buff));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
static SSL_SESSION * ssl_sess_deserialize(const struct asn1_sess* asn1)
|
||||||
|
{
|
||||||
|
SSL_SESSION *sess=NULL;
|
||||||
|
sess = d2i_SSL_SESSION(NULL, &(asn1->buff), asn1->size); /* increments asn1 */
|
||||||
|
return sess;
|
||||||
|
}
|
||||||
|
static int ssl_sess_varify_cb(void *data, int eliminate_type)
|
||||||
|
{
|
||||||
|
SSL_SESSION *sess=NULL;
|
||||||
|
int ret=0;
|
||||||
|
const struct asn1_sess* asn1=(struct asn1_sess*)data;
|
||||||
|
if(eliminate_type==ELIMINATE_TYPE_NUM)
|
||||||
|
{
|
||||||
|
return 1; //direct expired.
|
||||||
|
}
|
||||||
|
sess=ssl_sess_deserialize(asn1);
|
||||||
|
ret=ssl_session_is_valid(sess);
|
||||||
|
SSL_SESSION_free(sess);
|
||||||
|
if(ret==0)
|
||||||
|
{
|
||||||
|
return 1; //should be expired (deleted).
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long sess_cache_get_cb(void *data, const uchar *key, uint size, void *user_arg)
|
||||||
|
{
|
||||||
|
SSL_SESSION *sess=NULL;
|
||||||
|
int is_valid=0;
|
||||||
|
if(data==NULL)
|
||||||
|
{
|
||||||
|
return SESS_CACHE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
const struct asn1_sess* asn1=(struct asn1_sess*)data;
|
||||||
|
sess=ssl_sess_deserialize(data,asn1);
|
||||||
|
is_valid=ssl_session_is_valid(sess);
|
||||||
|
if(is_valid==0)
|
||||||
|
{
|
||||||
|
SSL_SESSION_free(sess);
|
||||||
|
return SESS_CACHE_INVALID;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(SSL_SESSION **)user_arg=sess;
|
||||||
|
return SESS_CACHE_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long sess_cache_set_cb(void *data, const uchar *key, uint size, void *user_arg)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct sess_set_args* args=(struct sess_set_args*)user_arg;
|
||||||
|
struct asn1_sess* new_asn1=args->new_sess;
|
||||||
|
struct asn1_sess *cur_asn1=(struct asn1_sess*)data;
|
||||||
|
int ret=0;
|
||||||
|
if(cur_asn1!=NULL)
|
||||||
|
{
|
||||||
|
free(cur_asn1->buff);
|
||||||
|
cur_asn1->size=new_asn1->size;
|
||||||
|
cur_asn1->buff=ALLOC(unsigned char, cur_asn1->size);
|
||||||
|
memcpy(cur_asn1->buff,new_asn1->buff,cur_asn1->size);
|
||||||
|
return SESS_CACHE_UPDATE_OLD;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret=MESA_htable_add(args->hash, key, size, new_asn1);
|
||||||
|
assert(ret>=0);
|
||||||
|
return SESS_CACHE_ADD_NEW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int upsess_mk_key(struct sockaddr * addr, socklen_t addr_len, const char* sni, unsigned char** key_buf)
|
||||||
|
{
|
||||||
|
size_t key_size=0;
|
||||||
|
unsigned char* tmp=NULL, p=NULL;
|
||||||
|
size_t tmp_size;
|
||||||
|
dynbuf_t tmp, *db;
|
||||||
|
short port;
|
||||||
|
size_t snilen;
|
||||||
|
|
||||||
|
switch (((struct sockaddr_storage *)addr)->ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
tmp = (unsigned char *)
|
||||||
|
&((struct sockaddr_in*)addr)->sin_addr;
|
||||||
|
tmp_size = sizeof(struct in_addr);
|
||||||
|
port = ((struct sockaddr_in*)addr)->sin_port;
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
tmp = (unsigned char *)
|
||||||
|
&((struct sockaddr_in6*)addr)->sin6_addr;
|
||||||
|
tmp_size = sizeof(struct in6_addr);
|
||||||
|
port = ((struct sockaddr_in6*)addr)->sin6_port;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//should never happens.
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
snilen = sni ? strlen(sni) : 0;
|
||||||
|
key_size=tmp_size+sizeof(port)+snilen;
|
||||||
|
*key_buf=ALLOC(unsigned char, key_size);
|
||||||
|
p=*key_buff;
|
||||||
|
memcpy(p,tmp,tmp_size);
|
||||||
|
p+=tmp_size;
|
||||||
|
memcpy(p, (char*)&port, sizeof(port));
|
||||||
|
p+=sizeof(port);
|
||||||
|
return key_size;
|
||||||
|
|
||||||
|
}
|
||||||
|
void up_session_set(struct sess_cache* cache, struct sockaddr * addr, socklen_t addr_len, const char* sni, SSL_SESSION * sess)
|
||||||
|
{
|
||||||
|
char* key=NULL;
|
||||||
|
int ret=0;
|
||||||
|
size_t key_size=0;
|
||||||
|
long cb_ret=0;
|
||||||
|
void* no_use=NULL;
|
||||||
|
assert(cache->served_for==CONN_DIR_UPSTREAM);
|
||||||
|
key_size=upsess_mk_key(addr, addr_len, sni, &key);
|
||||||
|
struct asn1_sess* asn1=NULL;
|
||||||
|
asn1=ssl_sess_serialize(sess);
|
||||||
|
|
||||||
|
struct sess_set_args set_args;
|
||||||
|
set_args.hash=cache->hash;
|
||||||
|
set_args.new_sess=asn1;
|
||||||
|
no_use=MESA_htable_search_cb(cache->hash, key, key_size, sess_cache_set_cb, &set_args,&cb_ret);
|
||||||
|
if(cb_ret==SESS_CACHE_UPDATE_OLD)
|
||||||
|
{
|
||||||
|
ssl_sess_free_serialized(asn1);
|
||||||
|
}
|
||||||
|
free(key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SSL_SESSION* up_session_get(struct sess_cache* cache, struct sockaddr * addr, socklen_t addr_len, const char* sni)
|
||||||
|
{
|
||||||
|
SSL_SESSION* sess=NULL;
|
||||||
|
void* no_use=NULL;
|
||||||
|
long cb_ret=0;
|
||||||
|
char* key=NULL;
|
||||||
|
size_t key_size=0;
|
||||||
|
assert(cache->served_for==CONN_DIR_UPSTREAM);
|
||||||
|
key_size=upsess_mk_key(addr, addr_len, sni, &key);
|
||||||
|
no_use=MESA_htable_search_cb(cache->hash, key, key_size,sess_cache_get_cb, &sess, &cb_ret);
|
||||||
|
free(key);
|
||||||
|
key=NULL;
|
||||||
|
if(cb_ret==1)
|
||||||
|
{
|
||||||
|
cache->hit_cnt++;
|
||||||
|
return sess;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cache->miss_cnt++;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void down_session_set(struct sess_cache* cache, const SSL_SESSION* sess)
|
||||||
|
{
|
||||||
|
unsigned int idlen=0;
|
||||||
|
struct asn1_sess* asn1=NULL;
|
||||||
|
long cb_ret=0;
|
||||||
|
void* no_use=NULL;
|
||||||
|
int ret=0;
|
||||||
|
assert(cache->served_for==CONN_DIR_DOWNSTREAM);
|
||||||
|
asn1=ssl_sess_serialize(sess);
|
||||||
|
/*
|
||||||
|
* SSL_SESSION_get_id() returns a pointer to the internal session id value for the session s.
|
||||||
|
* The length of the id in bytes is stored in *idlen. The length may be 0.
|
||||||
|
* The caller should not free the returned pointer directly.
|
||||||
|
*/
|
||||||
|
const unsigned char* id = SSL_SESSION_get_id(sess, &idlen);
|
||||||
|
struct sess_set_args set_args;
|
||||||
|
set_args.hash=cache->hash;
|
||||||
|
set_args.new_sess=asn1;
|
||||||
|
no_use=MESA_htable_search_cb(cache->hash, id, (unsigned int)idlen, sess_cache_set_cb, &set_args,&cb_ret);
|
||||||
|
if(cb_ret==SESS_CACHE_UPDATE_OLD)
|
||||||
|
{
|
||||||
|
ssl_sess_free_serialized(asn1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SSL_SESSION* down_session_get(struct sess_cache* cache, unsigned char * id, int idlen)
|
||||||
|
{
|
||||||
|
SSL_SESSION* sess=NULL;
|
||||||
|
void* no_use=NULL;
|
||||||
|
long cb_ret=0;
|
||||||
|
assert(cache->served_for==CONN_DIR_DOWNSTREAM);
|
||||||
|
no_use=MESA_htable_search_cb(cache->hash, id, (unsigned int)idlen, sess_cache_get_cb, &sess,&cb_ret);
|
||||||
|
if(cb_ret==1)
|
||||||
|
{
|
||||||
|
cache->hit_cnt++;
|
||||||
|
return sess;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cache->miss_cnt++;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void down_session_del(struct sess_cache* cache, const SSL_SESSION* sess)
|
||||||
|
{
|
||||||
|
assert(cache->served_for==CONN_DIR_DOWNSTREAM);
|
||||||
|
unsigned int len=0;
|
||||||
|
const unsigned char* id = SSL_SESSION_get_id(sess, &len);
|
||||||
|
int ret=MESA_htable_del(cache->hash, id, len, NULL);
|
||||||
|
if(ret!=MESA_HTABLE_RET_OK)
|
||||||
|
{
|
||||||
|
cache->del_err++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct sess_cache* ssl_sess_cache_create(int slot_size, int expire_seconds, enum tfe_conn_dir served)
|
||||||
|
{
|
||||||
|
struct sess_cache* cache=ALLOC(struct sess_cache, 1);
|
||||||
|
MESA_htable_handle htable=NULL;
|
||||||
|
int ret=0,max_num=slot_size*4;
|
||||||
|
htable=MESA_htable_born();
|
||||||
|
value=0;//no print
|
||||||
|
ret=MESA_htable_set_opt(htable, MHO_SCREEN_PRINT_CTRL, &(value), sizeof(value));
|
||||||
|
value=1;//thread safe
|
||||||
|
ret=MESA_htable_set_opt(htable, MHO_THREAD_SAFE, value, sizeof(value));
|
||||||
|
assert(ret==0);
|
||||||
|
value=16;
|
||||||
|
ret=MESA_htable_set_opt(htable, MHO_MUTEX_NUM, value, sizeof(value));
|
||||||
|
ret=MESA_htable_set_opt(htable, MHO_HASH_SLOT_SIZE, &(slot_size), sizeof(slot_size));
|
||||||
|
ret=MESA_htable_set_opt(htable, MHO_HASH_MAX_ELEMENT_NUM, &(max_num), sizeof(max_num));
|
||||||
|
ret=MESA_htable_set_opt(htable, MHO_EXPIRE_TIME, &(expire_seconds), sizeof(expire_seconds));
|
||||||
|
value=HASH_ELIMINATE_ALGO_FIFO;
|
||||||
|
ret=MESA_htable_set_opt(htable, MHO_ELIMIMINATE_TYPE, &(value), sizeof(value));
|
||||||
|
ret=MESA_htable_set_opt(htable, MHO_CBFUN_DATA_FREE, ssl_sess_free_serialized, sizeof(ssl_sess_free_serialized));
|
||||||
|
ret=MESA_htable_set_opt(htable, MHO_CBFUN_DATA_EXPIRE_NOTIFY, ssl_sess_varify_cb, sizeof(ssl_sess_varify_cb));
|
||||||
|
assert(ret==0);
|
||||||
|
ret=MESA_htable_mature(htable);
|
||||||
|
assert(ret==0);
|
||||||
|
cache->hash=htable;
|
||||||
|
cache->served_for=served;
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
void ssl_sess_cache_destroy(struct sess_cache* cache)
|
||||||
|
{
|
||||||
|
MESA_htable_destroy(cache->hash, NULL);
|
||||||
|
cache->hash=NULL;
|
||||||
|
free(cache);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
15
platform/src/ssl_sess_cache.h
Normal file
15
platform/src/ssl_sess_cache.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
|
#include <tfe_stream.h>
|
||||||
|
|
||||||
|
struct sess_cache;
|
||||||
|
struct sess_cache* ssl_sess_cache_create(int slot_size, int expire_seconds, enum tfe_conn_dir served);
|
||||||
|
void ssl_sess_cache_destroy(struct sess_cache* cache);
|
||||||
|
|
||||||
|
void up_session_set(struct sess_cache* cache, struct sockaddr * addr, socklen_t addr_len, const char* sni, SSL_SESSION * value)
|
||||||
|
SSL_SESSION* up_session_get(struct sess_cache* cache, struct sockaddr *addr, socklen_t addr_len, const char* sni);
|
||||||
|
void down_session_set(struct sess_cache* cache, const SSL_SESSION* sess);
|
||||||
|
SSL_SESSION* down_session_get(struct sess_cache* cache, unsigned char * id, int idlen);
|
||||||
|
|
||||||
Reference in New Issue
Block a user