mirror of
https://github.com/sonertari/SSLproxy
synced 2024-11-19 21:25:28 +00:00
Merge branch 'feature/starttls' of https://github.com/RichardPoole42/sslsplit into feature/autossl
This commit is contained in:
commit
96b038ef9b
14
opts.c
14
opts.c
@ -123,7 +123,7 @@ opts_has_ssl_spec(opts_t *opts)
|
||||
proxyspec_t *p = opts->spec;
|
||||
|
||||
while (p) {
|
||||
if (p->ssl)
|
||||
if (p->ssl || p->tlspeek)
|
||||
return 1;
|
||||
p = p->next;
|
||||
}
|
||||
@ -284,18 +284,27 @@ proxyspec_parse(int *argc, char **argv[], const char *natengine)
|
||||
if (!strcmp(**argv, "tcp")) {
|
||||
spec->ssl = 0;
|
||||
spec->http = 0;
|
||||
spec->tlspeek = 0;
|
||||
} else
|
||||
if (!strcmp(**argv, "ssl")) {
|
||||
spec->ssl = 1;
|
||||
spec->http = 0;
|
||||
spec->tlspeek = 0;
|
||||
} else
|
||||
if (!strcmp(**argv, "http")) {
|
||||
spec->ssl = 0;
|
||||
spec->http = 1;
|
||||
spec->tlspeek = 0;
|
||||
} else
|
||||
if (!strcmp(**argv, "https")) {
|
||||
spec->ssl = 1;
|
||||
spec->http = 1;
|
||||
spec->tlspeek = 0;
|
||||
} else
|
||||
if (!strcmp(**argv, "genericstarttls")) {
|
||||
spec->ssl = 0;
|
||||
spec->http = 0;
|
||||
spec->tlspeek = 1;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown connection "
|
||||
"type '%s'\n", **argv);
|
||||
@ -459,9 +468,10 @@ proxyspec_str(proxyspec_t *spec)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (asprintf(&s, "[%s]:%s %s %s %s", lhbuf, lpbuf,
|
||||
if (asprintf(&s, "[%s]:%s %s %s %s %s", lhbuf, lpbuf,
|
||||
(spec->ssl ? "ssl" : "tcp"),
|
||||
(spec->http ? "http" : "plain"),
|
||||
(spec->tlspeek ? "peeking" : ""),
|
||||
(spec->natengine ? spec->natengine : cbuf)) < 0) {
|
||||
s = NULL;
|
||||
}
|
||||
|
1
opts.h
1
opts.h
@ -39,6 +39,7 @@
|
||||
typedef struct proxyspec {
|
||||
unsigned int ssl : 1;
|
||||
unsigned int http : 1;
|
||||
unsigned int tlspeek: 1;
|
||||
struct sockaddr_storage listen_addr;
|
||||
socklen_t listen_addrlen;
|
||||
/* connect_addr and connect_addrlen are set: static mode;
|
||||
|
69
pxyconn.c
69
pxyconn.c
@ -128,6 +128,8 @@ typedef struct pxy_conn_ctx {
|
||||
unsigned int ocsp_denied : 1; /* 1 if OCSP was denied */
|
||||
unsigned int enomem : 1; /* 1 if out of memory */
|
||||
unsigned int sni_peek_retries : 6; /* max 64 SNI parse retries */
|
||||
unsigned int looking_for_client_hello : 1; /* 1 if waiting for hello */
|
||||
unsigned int pending_ssl_upgrade : 1; /* 1 if ssl upgrade in progress */
|
||||
|
||||
/* server name indicated by client in SNI TLS extension */
|
||||
char *sni;
|
||||
@ -198,6 +200,10 @@ pxy_conn_ctx_new(proxyspec_t *spec, opts_t *opts,
|
||||
memset(ctx, 0, sizeof(pxy_conn_ctx_t));
|
||||
ctx->spec = spec;
|
||||
ctx->opts = opts;
|
||||
ctx->looking_for_client_hello = spec->tlspeek;
|
||||
if (OPTS_DEBUG(opts)) {
|
||||
log_dbg_printf("looking status is %d\n", ctx->looking_for_client_hello);
|
||||
}
|
||||
ctx->fd = fd;
|
||||
ctx->thridx = pxy_thrmgr_attach(thrmgr, &ctx->evbase, &ctx->dnsbase);
|
||||
ctx->thrmgr = thrmgr;
|
||||
@ -1505,6 +1511,50 @@ deny:
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pxy_conn_check_and_upgrade(pxy_conn_ctx_t *ctx)
|
||||
{
|
||||
struct evbuffer *inbuf;
|
||||
struct evbuffer_iovec vec_out[1];
|
||||
if (OPTS_DEBUG(ctx->opts)) {
|
||||
log_dbg_printf("Checking for a client hello\n");
|
||||
}
|
||||
/* peek the buffer */
|
||||
inbuf = bufferevent_get_input(ctx->src.bev);
|
||||
if(evbuffer_peek(inbuf, 1024, 0, vec_out, 1)) {
|
||||
if(ssl_tls_clienthello_identify(vec_out->iov_base, &(vec_out->iov_len))) {
|
||||
if (OPTS_DEBUG(ctx->opts)) {
|
||||
log_dbg_printf("Found a clienthello in midstream\n");
|
||||
}
|
||||
ctx->dst.ssl = pxy_dstssl_create(ctx);
|
||||
if(!ctx->dst.ssl) {
|
||||
log_err_printf("Error creating SSL for upgrade\n");
|
||||
return 0;
|
||||
}
|
||||
ctx->dst.bev = bufferevent_openssl_filter_new(ctx->evbase, ctx->dst.bev, ctx->dst.ssl, BUFFEREVENT_SSL_CONNECTING, 0);
|
||||
bufferevent_setcb(ctx->dst.bev, pxy_bev_readcb, pxy_bev_writecb, pxy_bev_eventcb, ctx);
|
||||
bufferevent_enable(ctx->dst.bev, EV_READ|EV_WRITE);
|
||||
if(!ctx->dst.bev) {
|
||||
return 0;
|
||||
}
|
||||
if( OPTS_DEBUG(ctx->opts)) {
|
||||
log_err_printf("Replaced dst bufferevent, new one is %p\n", ctx->dst.bev);
|
||||
}
|
||||
|
||||
ctx->spec->ssl = 1;
|
||||
ctx->looking_for_client_hello = 0;
|
||||
ctx->pending_ssl_upgrade = 1;
|
||||
return 1;
|
||||
} else {
|
||||
if (OPTS_DEBUG(ctx->opts)) {
|
||||
log_dbg_printf("checked buffer, no client hello found\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
pxy_conn_terminate_free(pxy_conn_ctx_t *ctx)
|
||||
{
|
||||
@ -1544,6 +1594,12 @@ pxy_bev_readcb(struct bufferevent *bev, void *arg)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(ctx->looking_for_client_hello) {
|
||||
if(pxy_conn_check_and_upgrade(ctx)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct evbuffer *inbuf = bufferevent_get_input(bev);
|
||||
if (other->closed) {
|
||||
evbuffer_drain(inbuf, evbuffer_get_length(inbuf));
|
||||
@ -1772,8 +1828,21 @@ pxy_bev_eventcb(struct bufferevent *bev, short events, void *arg)
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(ctx->pending_ssl_upgrade) {
|
||||
if (OPTS_DEBUG(ctx->opts)) {
|
||||
log_dbg_printf("completing ssl upgrade\n");
|
||||
}
|
||||
ctx->src.bev = bufferevent_openssl_filter_new(ctx->evbase,
|
||||
ctx->src.bev, ctx->src.ssl,
|
||||
BUFFEREVENT_SSL_ACCEPTING, BEV_OPT_DEFER_CALLBACKS);
|
||||
bufferevent_setcb(ctx->src.bev, pxy_bev_readcb,
|
||||
pxy_bev_writecb, pxy_bev_eventcb, ctx);
|
||||
bufferevent_enable(ctx->src.bev, EV_READ|EV_WRITE);
|
||||
ctx->pending_ssl_upgrade = 0;
|
||||
} else {
|
||||
ctx->src.bev = pxy_bufferevent_setup(ctx, ctx->fd,
|
||||
ctx->src.ssl);
|
||||
}
|
||||
if (!ctx->src.bev) {
|
||||
if (ctx->src.ssl) {
|
||||
SSL_free(ctx->src.ssl);
|
||||
|
82
ssl.c
82
ssl.c
@ -1902,6 +1902,88 @@ out:
|
||||
DBG_printf("%zd bytes unparsed\n", n);
|
||||
return servername;
|
||||
}
|
||||
|
||||
int
|
||||
ssl_tls_clienthello_identify(const unsigned char *buf, ssize_t *sz)
|
||||
{
|
||||
#ifdef DEBUG_SNI_PARSER
|
||||
#define DBG_printf(...) log_dbg_printf("SNI Parser: " __VA_ARGS__)
|
||||
#else /* !DEBUG_SNI_PARSER */
|
||||
#define DBG_printf(...)
|
||||
#endif /* !DEBUG_SNI_PARSER */
|
||||
const unsigned char *p = buf;
|
||||
ssize_t n = *sz;
|
||||
|
||||
DBG_printf("buffer length %zd\n", n);
|
||||
|
||||
if (n < 1) {
|
||||
*sz = -1;
|
||||
goto out2;
|
||||
}
|
||||
DBG_printf("byte 0: %02x\n", *p);
|
||||
/* first byte 0x80, third byte 0x01 is SSLv2 clientHello;
|
||||
* first byte 0x22, second byte 0x03 is SSLv3/TLSv1.x clientHello */
|
||||
if (*p != 22) /* record type: handshake protocol */
|
||||
goto out2;
|
||||
p++; n--;
|
||||
|
||||
if (n < 2) {
|
||||
*sz = -1;
|
||||
goto out2;
|
||||
}
|
||||
DBG_printf("version: %02x %02x\n", p[0], p[1]);
|
||||
if (p[0] != 3)
|
||||
goto out2;
|
||||
p += 2; n -= 2;
|
||||
|
||||
if (n < 2) {
|
||||
*sz = -1;
|
||||
goto out2;
|
||||
}
|
||||
DBG_printf("length: %02x %02x\n", p[0], p[1]);
|
||||
#ifdef DEBUG_SNI_PARSER
|
||||
ssize_t recordlen = p[1] + (p[0] << 8);
|
||||
DBG_printf("recordlen=%zd\n", recordlen);
|
||||
#endif /* DEBUG_SNI_PARSER */
|
||||
p += 2; n -= 2;
|
||||
|
||||
if (n < 1) {
|
||||
*sz = -1;
|
||||
goto out2;
|
||||
}
|
||||
DBG_printf("message type: %i\n", *p);
|
||||
if (*p != 1) /* message type: ClientHello */
|
||||
goto out2;
|
||||
p++; n--;
|
||||
|
||||
if (n < 3) {
|
||||
*sz = -1;
|
||||
goto out2;
|
||||
}
|
||||
DBG_printf("message len: %02x %02x %02x\n", p[0], p[1], p[2]);
|
||||
ssize_t msglen = p[2] + (p[1] << 8) + (p[0] << 16);
|
||||
DBG_printf("msglen=%zd\n", msglen);
|
||||
if (msglen < 4)
|
||||
goto out2;
|
||||
p += 3; n -= 3;
|
||||
|
||||
if (n < msglen) {
|
||||
*sz = -1;
|
||||
goto out2;
|
||||
}
|
||||
n = msglen; /* only parse first message */
|
||||
|
||||
if (n < 2)
|
||||
goto out2;
|
||||
DBG_printf("clienthello version %02x %02x\n", p[0], p[1]);
|
||||
if (p[0] != 3)
|
||||
goto out2;
|
||||
p += 2; n -= 2;
|
||||
return 1;
|
||||
out2:
|
||||
DBG_printf("%zd bytes unparsed\n", n);
|
||||
return 0;
|
||||
}
|
||||
#endif /* !OPENSSL_NO_TLSEXT */
|
||||
|
||||
/* vim: set noet ft=c: */
|
||||
|
2
ssl.h
2
ssl.h
@ -167,6 +167,8 @@ int ssl_is_ocspreq(const unsigned char *, size_t) NONNULL(1) WUNRES;
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
char * ssl_tls_clienthello_parse_sni(const unsigned char *, ssize_t *)
|
||||
NONNULL(1,2) MALLOC;
|
||||
int ssl_tls_clienthello_identify(const unsigned char *, ssize_t *)
|
||||
NONNULL(1,2);
|
||||
#endif /* !OPENSSL_NO_TLSEXT */
|
||||
int ssl_dnsname_match(const char *, size_t, const char *, size_t)
|
||||
NONNULL(1,3) WUNRES;
|
||||
|
@ -332,6 +332,9 @@ SNI DNS lookup):
|
||||
.br
|
||||
\fBtcp\fP \fIlistenaddr port\fP
|
||||
[\fInat-engine\fP|\fIfwdaddr port\fP]
|
||||
.br
|
||||
\fBgenericstarttls\fP \fIlistenaddr port\fP
|
||||
[\fInat-engine\fP|\fIfwdaddr port\fP]
|
||||
.ad
|
||||
.TP
|
||||
\fBhttps\fP
|
||||
@ -350,6 +353,11 @@ the removal of HPKP, HSTS and Alternate Protocol response headers.
|
||||
Plain TCP connection without SSL/TLS and without any lower level protocol
|
||||
decoding; decrypted connection content is treated as opaque stream of bytes
|
||||
and not modified.
|
||||
.TP
|
||||
\fBgenericstarttls\fP
|
||||
Plain TCP connection until an SSL client hello appears in the byte stream;
|
||||
then starts SSL/TLS interception.
|
||||
|
||||
.TP
|
||||
.I listenaddr port
|
||||
IPv4 or IPv6 address and port or service name to listen on. This is the
|
||||
|
Loading…
Reference in New Issue
Block a user