From 63a48308cd1a35cb110c1abdc255e8acd3a5084b Mon Sep 17 00:00:00 2001 From: Soner Tari Date: Mon, 11 Apr 2022 01:11:04 +0300 Subject: [PATCH] Fix autossl without STARTTLS in divert mode In the previous implementation, the use case for autossl was assumed to be STARTTLS with POP3 or SMTP. But there are users who use autossl with HTTP too. The split mode was fine, but the divert mode was broken. This change makes autossl a generic upgrade mechanism. Also fix sslproxy line in autossl, change p to s if upgraded. Add e2e tests for autossl in divert and split mode. --- src/protoautossl.c | 104 ++++++++++++++---- src/protossl.c | 8 +- src/protossl.h | 3 +- src/prototcp.c | 9 +- src/prototcp.h | 1 - src/pxyconn.c | 83 ++++++++------- src/pxyconn.h | 5 + tests/testproxy/autossl_testset_1.json | 140 +++++++++++++++++++++++++ tests/testproxy/autossl_testset_2.json | 140 +++++++++++++++++++++++++ tests/testproxy/sslproxy.conf | 4 + tests/testproxy/testharness.json | 7 ++ 11 files changed, 437 insertions(+), 67 deletions(-) create mode 100644 tests/testproxy/autossl_testset_1.json create mode 100644 tests/testproxy/autossl_testset_2.json diff --git a/src/protoautossl.c b/src/protoautossl.c index 7636a43..86dc1ab 100644 --- a/src/protoautossl.c +++ b/src/protoautossl.c @@ -136,32 +136,60 @@ protoautossl_setup_dst_new_bev_ssl_connecting(pxy_conn_ctx_t *ctx) return 0; } +static void NONNULL(1) +protoautossl_upgrade_dst(pxy_conn_ctx_t *ctx) +{ + if (protossl_setup_dst_ssl(ctx) == -1) { + return; + } + if (protoautossl_setup_dst_new_bev_ssl_connecting(ctx) == -1) { + return; + } + bufferevent_setcb(ctx->dst.bev, pxy_bev_readcb, pxy_bev_writecb, pxy_bev_eventcb, ctx); +} + static int NONNULL(1) WUNRES -protoautossl_setup_dst_new_bev_ssl_connecting_child(pxy_conn_child_ctx_t *ctx) +protoautossl_setup_srvdst_new_bev_ssl_connecting(pxy_conn_ctx_t *ctx) { - ctx->dst.bev = bufferevent_openssl_filter_new(ctx->conn->thr->evbase, ctx->dst.bev, ctx->dst.ssl, + ctx->srvdst.bev = bufferevent_openssl_filter_new(ctx->thr->evbase, ctx->srvdst.bev, ctx->srvdst.ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS); - if (!ctx->dst.bev) { - log_err_level_printf(LOG_CRIT, "Error creating dst bufferevent\n"); - SSL_free(ctx->dst.ssl); - ctx->dst.ssl = NULL; - pxy_conn_term(ctx->conn, 1); + if (!ctx->srvdst.bev) { + log_err_level_printf(LOG_CRIT, "Error creating srvdst bufferevent\n"); + SSL_free(ctx->srvdst.ssl); + ctx->srvdst.ssl = NULL; + pxy_conn_term(ctx, 1); return -1; } - ctx->dst.free = protoautossl_bufferevent_free_and_close_fd; + ctx->srvdst.free = protoautossl_bufferevent_free_and_close_fd; return 0; } static void NONNULL(1) -protoautossl_upgrade_dst(pxy_conn_ctx_t *ctx) +protoautossl_upgrade_srvdst(pxy_conn_ctx_t *ctx) { - if (protossl_setup_dst_ssl(ctx) == -1) { + if (protossl_setup_srvdst_ssl(ctx) == -1) { return; } - if (protoautossl_setup_dst_new_bev_ssl_connecting(ctx) == -1) { + if (protoautossl_setup_srvdst_new_bev_ssl_connecting(ctx) == -1) { return; } - bufferevent_setcb(ctx->dst.bev, pxy_bev_readcb, pxy_bev_writecb, pxy_bev_eventcb, ctx); + bufferevent_setcb(ctx->srvdst.bev, pxy_bev_readcb, pxy_bev_writecb, pxy_bev_eventcb, ctx); +} + +static int NONNULL(1) WUNRES +protoautossl_setup_dst_new_bev_ssl_connecting_child(pxy_conn_child_ctx_t *ctx) +{ + ctx->dst.bev = bufferevent_openssl_filter_new(ctx->conn->thr->evbase, ctx->dst.bev, ctx->dst.ssl, + BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS); + if (!ctx->dst.bev) { + log_err_level_printf(LOG_CRIT, "Error creating dst bufferevent\n"); + SSL_free(ctx->dst.ssl); + ctx->dst.ssl = NULL; + pxy_conn_term(ctx->conn, 1); + return -1; + } + ctx->dst.free = protoautossl_bufferevent_free_and_close_fd; + return 0; } static void NONNULL(1) @@ -216,13 +244,26 @@ protoautossl_peek_and_upgrade(pxy_conn_ctx_t *ctx) if (ctx->divert) { if (!ctx->children) { // This means that there was no autossl handshake prior to ClientHello, e.g. no STARTTLS message - // This is perhaps the SSL handshake of a direct SSL connection, i.e. invalid protocol - log_err_level(LOG_CRIT, "No children setup yet, autossl protocol error"); - return -1; + // This is perhaps the SSL handshake of a direct SSL connection + log_err_level(LOG_CRIT, "No children setup yet, upgrading srvdst"); + protoautossl_upgrade_srvdst(ctx); + bufferevent_enable(ctx->srvdst.bev, EV_READ|EV_WRITE); + } + else { + // @attention Autossl protocol should never have multiple children. + log_err_level(LOG_CRIT, "Upgrading child dst"); + protoautossl_upgrade_dst_child(ctx->children); } - // @attention Autossl protocol should never have multiple children. - protoautossl_upgrade_dst_child(ctx->children); + // Change p in sslproxy_header to s + if (ctx->sslproxy_header) { + free(ctx->sslproxy_header); + ctx->sslproxy_header = NULL; + ctx->sslproxy_header_len = 0; + if (pxy_set_sslproxy_header(ctx, 1) == -1) { + return -1; + } + } } else { // srvdst == dst in split mode protoautossl_upgrade_dst(ctx); @@ -241,6 +282,19 @@ protoautossl_peek_and_upgrade(pxy_conn_ctx_t *ctx) return 0; } +static void NONNULL(1) +protoautossl_disable_srvdst(pxy_conn_ctx_t *ctx) +{ + log_finest("ENTER"); + + // Do not disable underlying bevs in autossl + bufferevent_setcb(ctx->srvdst.bev, NULL, NULL, NULL, NULL); + bufferevent_disable(ctx->srvdst.bev, EV_READ|EV_WRITE); + + // Do not access srvdst.bev from this point on + ctx->srvdst.bev = NULL; +} + static int NONNULL(1) WUNRES protoautossl_conn_connect(pxy_conn_ctx_t *ctx) { @@ -415,11 +469,14 @@ protoautossl_enable_conn_src(pxy_conn_ctx_t *ctx) bufferevent_setcb(ctx->src.bev, pxy_bev_readcb, pxy_bev_writecb, pxy_bev_eventcb, ctx); // Save the ssl info for logging, srvdst == dst in split mode - ctx->sslctx->srvdst_ssl_version = strdup(SSL_get_version(ctx->dst.ssl)); - ctx->sslctx->srvdst_ssl_cipher = strdup(SSL_get_cipher(ctx->dst.ssl)); + ctx->sslctx->srvdst_ssl_version = strdup(SSL_get_version(ctx->srvdst.ssl ? ctx->srvdst.ssl : ctx->dst.ssl)); + ctx->sslctx->srvdst_ssl_cipher = strdup(SSL_get_cipher(ctx->srvdst.ssl ? ctx->srvdst.ssl : ctx->dst.ssl)); // Now open the gates for a second time after autossl upgrade bufferevent_enable(ctx->src.bev, EV_READ|EV_WRITE); + + protoautossl_ctx_t *autossl_ctx = ctx->protoctx->arg; + autossl_ctx->clienthello_found = 0; return 0; } @@ -501,13 +558,16 @@ protoautossl_enable_conn_src_child(pxy_conn_child_ctx_t *ctx) bufferevent_setcb(ctx->conn->src.bev, pxy_bev_readcb, pxy_bev_writecb, pxy_bev_eventcb, ctx->conn); // srvdst is xferred to the first child conn, so save the ssl info for logging - ctx->conn->sslctx->srvdst_ssl_version = strdup(SSL_get_version(ctx->dst.ssl)); - ctx->conn->sslctx->srvdst_ssl_cipher = strdup(SSL_get_cipher(ctx->dst.ssl)); + ctx->conn->sslctx->srvdst_ssl_version = strdup(SSL_get_version(ctx->conn->srvdst.ssl ? ctx->conn->srvdst.ssl : ctx->dst.ssl)); + ctx->conn->sslctx->srvdst_ssl_cipher = strdup(SSL_get_cipher(ctx->conn->srvdst.ssl ? ctx->conn->srvdst.ssl : ctx->dst.ssl)); log_finer_va("Enabling ssl src, %s", ctx->conn->sslproxy_header); // Now open the gates for a second time after autossl upgrade bufferevent_enable(ctx->conn->src.bev, EV_READ|EV_WRITE); + + protoautossl_ctx_t *autossl_ctx = ctx->protoctx->arg; + autossl_ctx->clienthello_found = 0; return 0; } @@ -657,6 +717,8 @@ protoautossl_setup(pxy_conn_ctx_t *ctx) ctx->protoctx->set_watermarkcb = protoautossl_try_set_watermark; ctx->protoctx->unset_watermarkcb = protoautossl_try_unset_watermark; + ctx->protoctx->disable_srvdstcb = protoautossl_disable_srvdst; + ctx->protoctx->arg = malloc(sizeof(protoautossl_ctx_t)); if (!ctx->protoctx->arg) { return PROTO_ERROR; diff --git a/src/protossl.c b/src/protossl.c index 50e0d84..4be9b24 100644 --- a/src/protossl.c +++ b/src/protossl.c @@ -1449,7 +1449,7 @@ protossl_setup_dst_ssl(pxy_conn_ctx_t *ctx) return 0; } -static int NONNULL(1) +int protossl_setup_srvdst_ssl(pxy_conn_ctx_t *ctx) { ctx->srvdst.ssl = protossl_dstssl_create(ctx); @@ -1520,7 +1520,7 @@ protossl_connect_child(pxy_conn_child_ctx_t *ctx) ctx->dst = ctx->conn->srvdst; // See the comments in prototcp_setup_dst() - prototcp_disable_srvdst(ctx->conn); + ctx->conn->protoctx->disable_srvdstcb(ctx->conn); bufferevent_setcb(ctx->dst.bev, pxy_bev_readcb_child, pxy_bev_writecb_child, pxy_bev_eventcb_child, ctx); ctx->protoctx->bev_eventcb(ctx->dst.bev, BEV_EVENT_CONNECTED, ctx); @@ -1574,7 +1574,9 @@ protossl_setup_src_ssl_from_dst(pxy_conn_ctx_t *ctx) { // @attention We cannot engage passthrough mode upon ssl errors on already enabled src // This function is used by protoautossl only - if (ctx->src.ssl || (ctx->src.ssl = protossl_srcssl_create(ctx, ctx->dst.ssl))) { + // srvdst may or may not have been xfered to child, or it may be divert or split mode + // so make sure dst.ssl is not NULL + if (ctx->src.ssl || (ctx->src.ssl = protossl_srcssl_create(ctx, ctx->srvdst.ssl ? ctx->srvdst.ssl : ctx->dst.ssl))) { return 0; } else if (ctx->term) { diff --git a/src/protossl.h b/src/protossl.h index d473cb0..1289bc4 100644 --- a/src/protossl.h +++ b/src/protossl.h @@ -52,7 +52,8 @@ int protossl_setup_src_ssl_from_child_dst(pxy_conn_child_ctx_t *) NONNULL(1); int protossl_setup_dst_ssl(pxy_conn_ctx_t *) NONNULL(1); int protossl_setup_dst_ssl_child(pxy_conn_child_ctx_t *) NONNULL(1); -int protossl_setup_srvdst(pxy_conn_ctx_t *ctx) NONNULL(1); +int protossl_setup_srvdst_ssl(pxy_conn_ctx_t *) NONNULL(1); +int protossl_setup_srvdst(pxy_conn_ctx_t *) NONNULL(1); void protossl_bev_eventcb_srvdst(struct bufferevent *, short, pxy_conn_ctx_t *) NONNULL(1); diff --git a/src/prototcp.c b/src/prototcp.c index 773e53a..ae21046 100644 --- a/src/prototcp.c +++ b/src/prototcp.c @@ -111,9 +111,11 @@ prototcp_setup_src(pxy_conn_ctx_t *ctx) return 0; } -void +static void NONNULL(1) prototcp_disable_srvdst(pxy_conn_ctx_t *ctx) { + log_finest("ENTER"); + bufferevent_setcb(ctx->srvdst.bev, NULL, NULL, NULL, NULL); bufferevent_disable(ctx->srvdst.bev, EV_READ|EV_WRITE); @@ -151,7 +153,7 @@ prototcp_setup_dst(pxy_conn_ctx_t *ctx) // This seems to be an issue with libevent. // @todo Why does libevent raise the same event again for an already disabled and freed conn end? // Note again that srvdst == dst or child_dst here. - prototcp_disable_srvdst(ctx); + ctx->protoctx->disable_srvdstcb(ctx); bufferevent_setcb(ctx->dst.bev, pxy_bev_readcb, pxy_bev_writecb, pxy_bev_eventcb, ctx); ctx->protoctx->bev_eventcb(ctx->dst.bev, BEV_EVENT_CONNECTED, ctx); @@ -213,7 +215,7 @@ prototcp_connect_child(pxy_conn_child_ctx_t *ctx) ctx->dst = ctx->conn->srvdst; // See the comments in prototcp_setup_dst() - prototcp_disable_srvdst(ctx->conn); + ctx->conn->protoctx->disable_srvdstcb(ctx->conn); bufferevent_setcb(ctx->dst.bev, pxy_bev_readcb_child, pxy_bev_writecb_child, pxy_bev_eventcb_child, ctx); ctx->protoctx->bev_eventcb(ctx->dst.bev, BEV_EVENT_CONNECTED, ctx); @@ -988,6 +990,7 @@ prototcp_setup(pxy_conn_ctx_t *ctx) ctx->protoctx->set_watermarkcb = prototcp_try_set_watermark; ctx->protoctx->unset_watermarkcb = prototcp_try_unset_watermark; + ctx->protoctx->disable_srvdstcb = prototcp_disable_srvdst; return PROTO_TCP; } diff --git a/src/prototcp.h b/src/prototcp.h index dbff404..62d18d4 100644 --- a/src/prototcp.h +++ b/src/prototcp.h @@ -82,7 +82,6 @@ int prototcp_enable_src(pxy_conn_ctx_t *) NONNULL(1); void prototcp_bev_eventcb_srvdst(struct bufferevent *, short, pxy_conn_ctx_t *) NONNULL(1); int prototcp_setup_src(pxy_conn_ctx_t *) NONNULL(1); -void prototcp_disable_srvdst(pxy_conn_ctx_t *) NONNULL(1); int prototcp_setup_dst(pxy_conn_ctx_t *) NONNULL(1); int prototcp_setup_srvdst(pxy_conn_ctx_t *) NONNULL(1); diff --git a/src/pxyconn.c b/src/pxyconn.c index db3ea2c..8c4432a 100644 --- a/src/pxyconn.c +++ b/src/pxyconn.c @@ -1153,44 +1153,8 @@ pxy_opensock_child(pxy_conn_ctx_t *ctx) } int -pxy_setup_child_listener(pxy_conn_ctx_t *ctx) +pxy_set_sslproxy_header(pxy_conn_ctx_t *ctx, int upgraded) { - if (!ctx->divert) { - // split mode - return 0; - } - - // @attention Defer child setup and evcl creation until after parent init is complete, otherwise (1) causes multithreading issues (proxy_listener_acceptcb is - // running on a different thread from the conn, and we only have thrmgr mutex), and (2) we need to clean up less upon errors. - // Child evcls use the evbase of the parent thread, otherwise we would get multithreading issues. - // We don't need a privsep call to open a socket for child listener, - // because listener port of child conns are assigned by the system, hence are from non-privileged range above 1024 - ctx->child_fd = pxy_opensock_child(ctx); - if (ctx->child_fd < 0) { - log_err_level_printf(LOG_CRIT, "Error opening child socket: %s (%i)\n", strerror(errno), errno); - log_fine_va("Error opening child socket: %s (%i)", strerror(errno), errno); - pxy_conn_term(ctx, 1); - return -1; - } - ctx->thr->max_fd = max(ctx->thr->max_fd, ctx->child_fd); - - // @attention Do not pass NULL as user-supplied pointer - struct evconnlistener *child_evcl = evconnlistener_new(ctx->thr->evbase, pxy_listener_acceptcb_child, ctx, LEV_OPT_CLOSE_ON_FREE, 1024, ctx->child_fd); - if (!child_evcl) { - log_err_level_printf(LOG_CRIT, "Error creating child evconnlistener: %s\n", strerror(errno)); - log_fine_va("Error creating child evconnlistener: %s", strerror(errno)); - - // @attention Close child fd separately, because child evcl does not exist yet, hence fd would not be closed by calling pxy_conn_free() - evutil_closesocket(ctx->child_fd); - pxy_conn_term(ctx, 1); - return -1; - } - ctx->child_evcl = child_evcl; - - evconnlistener_set_error_cb(child_evcl, proxy_listener_errorcb); - - log_finer_va("Finished setting up child listener, child_fd=%d", ctx->child_fd); - struct sockaddr_in child_listener_addr; socklen_t child_listener_len = sizeof(child_listener_addr); @@ -1244,7 +1208,7 @@ pxy_setup_child_listener(pxy_conn_ctx_t *ctx) #endif /* !WITHOUT_USERAUTH */ , SSLPROXY_KEY, addr, port, STRORNONE(ctx->srchost_str), STRORNONE(ctx->srcport_str), - STRORNONE(ctx->dsthost_str), STRORNONE(ctx->dstport_str), ctx->spec->ssl ? "s":"p" + STRORNONE(ctx->dsthost_str), STRORNONE(ctx->dstport_str), ctx->spec->ssl || upgraded ? "s":"p" #ifndef WITHOUT_USERAUTH , user_len ? "," : "", user_len ? ctx->user : "" #endif /* !WITHOUT_USERAUTH */ @@ -1254,9 +1218,52 @@ pxy_setup_child_listener(pxy_conn_ctx_t *ctx) return -1; } log_finer_va("sslproxy_header= %s", ctx->sslproxy_header); + return 0; } +int +pxy_setup_child_listener(pxy_conn_ctx_t *ctx) +{ + if (!ctx->divert) { + // split mode + return 0; + } + + // @attention Defer child setup and evcl creation until after parent init is complete, otherwise (1) causes multithreading issues (proxy_listener_acceptcb is + // running on a different thread from the conn, and we only have thrmgr mutex), and (2) we need to clean up less upon errors. + // Child evcls use the evbase of the parent thread, otherwise we would get multithreading issues. + // We don't need a privsep call to open a socket for child listener, + // because listener port of child conns are assigned by the system, hence are from non-privileged range above 1024 + ctx->child_fd = pxy_opensock_child(ctx); + if (ctx->child_fd < 0) { + log_err_level_printf(LOG_CRIT, "Error opening child socket: %s (%i)\n", strerror(errno), errno); + log_fine_va("Error opening child socket: %s (%i)", strerror(errno), errno); + pxy_conn_term(ctx, 1); + return -1; + } + ctx->thr->max_fd = max(ctx->thr->max_fd, ctx->child_fd); + + // @attention Do not pass NULL as user-supplied pointer + struct evconnlistener *child_evcl = evconnlistener_new(ctx->thr->evbase, pxy_listener_acceptcb_child, ctx, LEV_OPT_CLOSE_ON_FREE, 1024, ctx->child_fd); + if (!child_evcl) { + log_err_level_printf(LOG_CRIT, "Error creating child evconnlistener: %s\n", strerror(errno)); + log_fine_va("Error creating child evconnlistener: %s", strerror(errno)); + + // @attention Close child fd separately, because child evcl does not exist yet, hence fd would not be closed by calling pxy_conn_free() + evutil_closesocket(ctx->child_fd); + pxy_conn_term(ctx, 1); + return -1; + } + ctx->child_evcl = child_evcl; + + evconnlistener_set_error_cb(child_evcl, proxy_listener_errorcb); + + log_finer_va("Finished setting up child listener, child_fd=%d", ctx->child_fd); + + return pxy_set_sslproxy_header(ctx, 0); +} + int pxy_try_close_conn_end(pxy_conn_desc_t *conn_end, pxy_conn_ctx_t *ctx) { diff --git a/src/pxyconn.h b/src/pxyconn.h index a8bf919..776a3e9 100644 --- a/src/pxyconn.h +++ b/src/pxyconn.h @@ -87,6 +87,8 @@ typedef void (*child_proto_free_func_t)(pxy_conn_child_ctx_t *); typedef void (*set_watermark_func_t)(struct bufferevent *, pxy_conn_ctx_t *, struct bufferevent *); typedef void (*unset_watermark_func_t)(struct bufferevent *, pxy_conn_ctx_t *, pxy_conn_desc_t *); +typedef void (*disable_srvdstcb)(pxy_conn_ctx_t *); + typedef filter_action_t * (*proto_filter_func_t)(pxy_conn_ctx_t *, filter_list_t *) NONNULL(1,2) WUNRES; /* @@ -174,6 +176,8 @@ struct proto_ctx { set_watermark_func_t set_watermarkcb; unset_watermark_func_t unset_watermarkcb; + disable_srvdstcb disable_srvdstcb; + // For protocol specific fields, if any void *arg; }; @@ -434,6 +438,7 @@ void pxy_conn_term(pxy_conn_ctx_t *, int) NONNULL(1); void pxy_conn_term_child(pxy_conn_child_ctx_t *) NONNULL(1); void pxy_conn_free_children(pxy_conn_ctx_t *) NONNULL(1); +int pxy_set_sslproxy_header(pxy_conn_ctx_t *, int) NONNULL(1); int pxy_setup_child_listener(pxy_conn_ctx_t *) NONNULL(1); int pxy_bev_readcb_preexec_logging_and_stats(struct bufferevent *, pxy_conn_ctx_t *) NONNULL(1,2); diff --git a/tests/testproxy/autossl_testset_1.json b/tests/testproxy/autossl_testset_1.json new file mode 100644 index 0000000..e784318 --- /dev/null +++ b/tests/testproxy/autossl_testset_1.json @@ -0,0 +1,140 @@ +{ + "comment": "Autossl tests for HTTP request headers: SSLproxy, Connection, Upgrade, Keep-Alive, Accept-Encoding, Via, X-Forwarded-For, and Referer", + "configs": { + "1": { + "proto": { + "proto": "tcp" + }, + "client": { + "ip": "127.0.0.1", + "port": "8214" + }, + "server": { + "ip": "127.0.0.1", + "port": "9214" + } + }, + "2": { + "proto": { + "proto": "ssl", + "crt": "server.crt", + "key": "server.key" + }, + "client": { + "ip": "127.0.0.1", + "port": "8214" + }, + "server": { + "ip": "127.0.0.1", + "port": "9214" + } + } + }, + "tests": { + "1": { + "comment": "Does not remove any extra SSLproxy line, nor appends Connection: close", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nSSLproxy: sslproxy\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nSSLproxy: sslproxy\r\n\r\n" + } + } + }, + "2": { + "comment": "Does not change Connection header to close", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: Keep-Alive\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: Keep-Alive\r\n\r\n" + } + } + }, + "3": { + "comment": "Does not suppress upgrading to SSL/TLS, WebSockets or HTTP/2", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nUpgrade: websocket\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nUpgrade: websocket\r\n\r\n" + } + } + }, + "4": { + "comment": "Does not remove Accept-Encoding", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nAccept-Encoding: encoding\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nAccept-Encoding: encoding\r\n\r\n" + } + } + }, + "5": { + "comment": "Does not remove Via", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nVia: via\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nVia: via\r\n\r\n" + } + } + }, + "6": { + "comment": "Does not remove X-Forwarded-For", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nX-Forwarded-For: x-forwarded-for\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nX-Forwarded-For: x-forwarded-for\r\n\r\n" + } + } + }, + "7": { + "comment": "Does not remove Referer", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nReferer: referer\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nReferer: referer\r\n\r\n" + } + } + } + } +} \ No newline at end of file diff --git a/tests/testproxy/autossl_testset_2.json b/tests/testproxy/autossl_testset_2.json new file mode 100644 index 0000000..47fdfdc --- /dev/null +++ b/tests/testproxy/autossl_testset_2.json @@ -0,0 +1,140 @@ +{ + "comment": "Autossl split mode tests for HTTP request headers: SSLproxy, Connection, Upgrade, Keep-Alive, Accept-Encoding, Via, X-Forwarded-For, and Referer", + "configs": { + "1": { + "proto": { + "proto": "tcp" + }, + "client": { + "ip": "127.0.0.1", + "port": "8215" + }, + "server": { + "ip": "127.0.0.1", + "port": "9215" + } + }, + "2": { + "proto": { + "proto": "ssl", + "crt": "server.crt", + "key": "server.key" + }, + "client": { + "ip": "127.0.0.1", + "port": "8215" + }, + "server": { + "ip": "127.0.0.1", + "port": "9215" + } + } + }, + "tests": { + "1": { + "comment": "Does not remove any extra SSLproxy line, nor appends Connection: close", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nSSLproxy: sslproxy\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nSSLproxy: sslproxy\r\n\r\n" + } + } + }, + "2": { + "comment": "Does not change Connection header to close", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: Keep-Alive\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: Keep-Alive\r\n\r\n" + } + } + }, + "3": { + "comment": "Does not suppress upgrading to SSL/TLS, WebSockets or HTTP/2", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nUpgrade: websocket\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nUpgrade: websocket\r\n\r\n" + } + } + }, + "4": { + "comment": "Does not remove Accept-Encoding", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nAccept-Encoding: encoding\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nAccept-Encoding: encoding\r\n\r\n" + } + } + }, + "5": { + "comment": "Does not remove Via", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nVia: via\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nVia: via\r\n\r\n" + } + } + }, + "6": { + "comment": "Does not remove X-Forwarded-For", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nX-Forwarded-For: x-forwarded-for\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nX-Forwarded-For: x-forwarded-for\r\n\r\n" + } + } + }, + "7": { + "comment": "Does not remove Referer", + "states": { + "1": { + "testend": "client", + "cmd": "send", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nReferer: referer\r\n\r\n" + }, + "2": { + "testend": "server", + "cmd": "recv", + "payload": "GET / HTTP/1.1\r\nHost: example.com\r\nReferer: referer\r\n\r\n" + } + } + } + } +} \ No newline at end of file diff --git a/tests/testproxy/sslproxy.conf b/tests/testproxy/sslproxy.conf index fa5d427..1a002ea 100644 --- a/tests/testproxy/sslproxy.conf +++ b/tests/testproxy/sslproxy.conf @@ -1751,3 +1751,7 @@ ProxySpec { MaxHTTPHeaderSize 8192 } } + +# Autossl tests for HTTP request headers: SSLproxy, Connection, Upgrade, Keep-Alive, Accept-Encoding, Via, X-Forwarded-For, and Referer +ProxySpec autossl 127.0.0.1 8214 up:8080 127.0.0.1 9214 +ProxySpec autossl 127.0.0.1 8215 127.0.0.1 9215 diff --git a/tests/testproxy/testharness.json b/tests/testproxy/testharness.json index 8d6d041..683ea6c 100644 --- a/tests/testproxy/testharness.json +++ b/tests/testproxy/testharness.json @@ -61,6 +61,13 @@ "13": "filter_struct_testset_1.json", "14": "filter_struct_reconnect_testset_1.json" } + }, + "6": { + "comment": "Autossl tests", + "testsets": { + "1": "autossl_testset_1.json", + "2": "autossl_testset_2.json" + } } } }