Merge branch 'feature-ssl-stream' into 'develop-tfe3a'

Feature ssl stream

See merge request tango/tfe!2
This commit is contained in:
郑超
2018-08-21 19:35:45 +08:00
5 changed files with 88 additions and 45 deletions

View File

@@ -8,8 +8,8 @@ enum e_future_error
struct promise;
struct future;
typedef void (future_success_cb)(void * result, void * user);
typedef void future_result_t;
typedef void (future_success_cb)(future_result_t* result, void * user);
typedef void (future_failed_cb)(enum e_future_error err, const char * what, void * user);
typedef void (promise_ctx_destroy_cb)(struct promise * p);

View File

@@ -0,0 +1,19 @@
#pragma once
#include "tfe_future.h"
struct ssl_client_hello
{
int version;
char* sni;
char* cipher_suites;
};
struct ssl_client_hello* ssl_get_peek_result(future_result_t* result);
void ssl_free_peek_result(struct ssl_client_hello* client_hello);
void ssl_async_peek_client_hello(struct future* future, evutil_socket_t fd, struct event_base *evbase);
void ssl_async_connect_origin(struct future* future, const struct ssl_client_hello* client_hello, evutil_socket_t fd, const char* sni, struct event_base *evbase);
struct ssl_downstream * ssl_downstream_create();
void ssl_upstream_free(struct ssl_upstream * p);
void ssl_downstream_free(struct ssl_downstream * p);

View File

@@ -116,11 +116,3 @@ struct tfe_stream_private * tfe_stream_create(evutil_socket_t fd_downstream, evu
void tfe_stream_setup(struct tfe_stream_private * _stream);
void ssl_async_connect_origin(struct future * future, evutil_socket_t fd, const char * sni,
struct event_base * evbase, struct tfe_config * opts);
void ssl_async_peek_sni(struct future * future, evutil_socket_t fd, struct event_base * evbase);
struct ssl_downstream * ssl_downstream_create();
void ssl_upstream_free(struct ssl_upstream * p);
void ssl_downstream_free(struct ssl_downstream * p);

View File

@@ -19,6 +19,7 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <tfe_stream.h>
#include <tfe_utils.h>
#include <tfe_future.h>
@@ -26,19 +27,17 @@
#include <cert.h>
#include <ssl.h>
struct peek_sni_ctx
struct peek_client_hello_ctx
{
/* ssl */
unsigned char sni_peek_retries; /* max 64 SNI parse retries */
char* sni;
struct event* ev;
struct event_base* evbase;
};
void peek_sni_ctx_free(void* ctx)
void peek_client_hello_ctx_free(void* ctx)
{
struct peek_sni_ctx * _ctx=(struct peek_sni_ctx *)ctx;
struct peek_client_hello_ctx * _ctx=(struct peek_client_hello_ctx *)ctx;
event_free(_ctx->ev);
_ctx->ev = NULL;
free(_ctx->sni);
@@ -46,13 +45,40 @@ void peek_sni_ctx_free(void* ctx)
free(_ctx);
return;
}
struct ssl_client_hello* ssl_get_peek_result(future_result_t* result)
{
struct ssl_client_hello* p=(struct ssl_client_hello* )result, *copy=NULL;
copy=ALLOC(struct ssl_client_hello*,1);
if(p!=NULL)
{
copy->sni=tfe_strdup(p->sni);
copy->cipher_suites=tfe_strdup(p->cipher_suites);
copy->version=p->version;
}
return copy;
}
void ssl_free_peek_result(struct ssl_client_hello* p)
{
if(p==NULL)
{
return;
}
free(p->sni);
p->sni=NULL;
free(p->cipher_suites);
p->cipher_suites=NULL;
p->cipher_suites=NULL;
free(p);
return;
}
static void peek_sni_cb(evutil_socket_t fd, short what, void * arg)
static void peek_client_hello_cb(evutil_socket_t fd, short what, void * arg)
{
struct promise* promise=(struct promise*)arg;
struct peek_sni_ctx* ctx= (struct peek_sni_ctx*)promise->ctx;
struct peek_client_hello_ctx* ctx= (struct peek_client_hello_ctx*)promise->ctx;
struct ssl_client_hello *result=NULL;
memset(&result, 0, sizeof(result));
char* sni=NULL;
unsigned char buf[1024];
ssize_t n=0;
@@ -62,19 +88,20 @@ static void peek_sni_cb(evutil_socket_t fd, short what, void * arg)
n = recv(fd, buf, sizeof(buf), MSG_PEEK);
if (n == -1)
{
goto promise_failed;
TFE_LOG_ERROR("Error peeking on fd, aborting connection\n");
goto failed;
}
if (n == 0)
goto promise_failed;
{
goto failed;
rv = ssl_tls_clienthello_parse(buf, n, 0, &chello, &ctx->sni);
}
result=ssl_get_peek_result(NULL);
//todo: parse version and cipher suites.
rv = ssl_tls_clienthello_parse(buf, n, 0, &chello, &result->sni);
if ((rv == 1) && !chello)
{
goto promise_failed;
TFE_LOG_ERROR("Peeking did not yield a (truncated) ClientHello message, aborting connection\n");
goto failed;
}
@@ -90,32 +117,37 @@ static void peek_sni_cb(evutil_socket_t fd, short what, void * arg)
* reading now. We use 25 * 0.2 s = 5 s timeout. */
struct timeval retry_delay = {0, 100};
ctx->ev = event_new(ctx->evbase, fd, 0, peek_sni_cb, promise);
event_free(ctx->ev);
ctx->ev = event_new(ctx->evbase, fd, 0, peek_client_hello_cb, promise);
assert(ctx->ev!=NULL);
event_add(ctx->ev, &retry_delay);
return;
}
promise_set_ctx(promise, NULL, NULL);
promise->f.cb_success(ctx->sni,promise->f.user);
peek_sni_ctx_free(ctx);
promise_dettach_ctx(promise);
promise_success(promise, result);
ssl_free_peek_result(result);
peek_client_hello_ctx_free(ctx);
promise_failed:
promise->f.cb_failed(FUTURE_ERROR_EXCEPTION,"too many tries",promise->f.user);
peek_sni_ctx_free(ctx);
promise_set_ctx(promise, NULL,NULL);
return;
failed:
promise_failed(promise,FUTURE_ERROR_EXCEPTION,"too many tries");
peek_client_hello_ctx_free(ctx);
promise_dettach_ctx(promise);
ssl_free_peek_result(result);
return;
}
void ssl_async_peek_sni( struct future* future, evutil_socket_t fd, struct event_base *evbase)
void ssl_async_peek_client_hello(struct future* future, evutil_socket_t fd, struct event_base *evbase)
{
struct event * ev=NULL;
struct peek_sni_ctx* ctx=ALLOC(struct peek_sni_ctx, 1);
ctx->ev = event_new(evbase, fd, EV_READ, peek_sni_cb, p);
struct promise* p=future_to_promise(future);
struct peek_client_hello_ctx* ctx=ALLOC(struct peek_client_hello_ctx, 1);
ctx->ev = event_new(evbase, fd, EV_READ, peek_client_hello_cb, p);
promise_set_ctx(p, ctx,peek_sni_ctx_free);
event_add(evbase, NULL);
promise_set_ctx(p, ctx, peek_client_hello_ctx_free);
return;
@@ -166,8 +198,7 @@ static void ssl_connect_origin_eventcb(struct bufferevent * bev, short events, v
ssl_connect_origin_ctx_free(ctx);
return
}
void ssl_async_connect_origin(struct future* future, evutil_socket_t fd, const char* sni,
struct event_base *evbase, struct tfe_config *opts)
void ssl_async_connect_origin(struct future* future, const struct ssl_client_hello* client_hello, evutil_socket_t fd, const char* sni, struct event_base *evbase)
{
struct promise* p=future_to_promise(future);
@@ -827,7 +858,8 @@ static int pxy_ossl_servername_cb(SSL * ssl, UNUSED int * al, void * arg)
/*
* Create new SSL context for outgoing connections to the original destination.
* If hostname sni is provided, use it for Server Name Indication.
static SSL* upstream_ssl_create(tfe_config*opts, const char* sni)
*/
static SSL* upstream_ssl_create(const struct ssl_client_hello* client_hello, int sslversion, const char* sni, MESA_htable_handle* dsess_cache)
{
SSL_CTX* sslctx=NULL;

View File

@@ -457,7 +457,7 @@ void ssl_conn_origin_on_fail(enum e_future_error err, const char * what, void *
assert(0);
}
void peek_sni_on_succ(void * result, void * user)
void peek_client_hello_on_succ(void * result, void * user)
{
struct tfe_stream_private * _stream = (struct tfe_stream_private *) user;
assert(_stream->session_type == SESSION_PROTO_SSL);
@@ -475,7 +475,7 @@ void peek_sni_on_succ(void * result, void * user)
_stream->thrmgr_ref->evbase, NULL);
}
void peek_sni_on_fail(enum e_future_error err, const char * what, void * user)
void peek_client_hello_on_fail(enum e_future_error err, const char * what, void * user)
{
//TODO:
assert(0);
@@ -501,8 +501,8 @@ void tfe_stream_setup(struct tfe_stream_private * _stream)
case SESSION_PROTO_SSL:
// for SSL, defer dst connection setup to initial_readcb
_stream->ssl_downstream = ssl_downstream_create();
_stream->async_future = future_create(peek_sni_on_succ, peek_sni_on_fail, _stream);
ssl_async_peek_sni(_stream->ssl_downstream->future_sni_peek, _stream->fd_downstream,
_stream->async_future = future_create(peek_client_hello_on_succ, peek_client_hello_on_fail, _stream);
ssl_async_peek_client_hello(_stream->ssl_downstream->future_sni_peek, _stream->fd_downstream,
_stream->thrmgr_ref->evbase);
thread->stat.value[SSL_NUM]++;
break;