From c4d743bb4d0cc045d41322169a4e36a151e247f1 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Thu, 14 Jun 2018 09:21:34 -0400 Subject: [PATCH] mod_sockproxy - socket forwarding (experimental) --- src/Makefile.am | 5 ++ src/connections.c | 1 + src/mod_sockproxy.c | 180 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 src/mod_sockproxy.c diff --git a/src/Makefile.am b/src/Makefile.am index 0e83f9e1e..655b5b69f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -258,6 +258,11 @@ mod_proxy_la_SOURCES = mod_proxy.c mod_proxy_la_LDFLAGS = $(common_module_ldflags) mod_proxy_la_LIBADD = $(common_libadd) +lib_LTLIBRARIES += mod_sockproxy.la +mod_sockproxy_la_SOURCES = mod_sockproxy.c +mod_sockproxy_la_LDFLAGS = $(common_module_ldflags) +mod_sockproxy_la_LIBADD = $(common_libadd) + lib_LTLIBRARIES += mod_ssi.la mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c mod_ssi_la_LDFLAGS = $(common_module_ldflags) diff --git a/src/connections.c b/src/connections.c index 6ed82b67f..6435e27aa 100644 --- a/src/connections.c +++ b/src/connections.c @@ -1128,6 +1128,7 @@ connection *connection_accepted(server *srv, server_socket *srv_socket, sock_add connection_close(srv, con); return NULL; } + if (con->http_status < 0) connection_set_state(srv, con, CON_STATE_WRITE); return con; } diff --git a/src/mod_sockproxy.c b/src/mod_sockproxy.c new file mode 100644 index 000000000..faaeb1d02 --- /dev/null +++ b/src/mod_sockproxy.c @@ -0,0 +1,180 @@ +#include "first.h" + +#include +#include + +#include "gw_backend.h" +typedef gw_plugin_config plugin_config; +typedef gw_plugin_data plugin_data; +typedef gw_handler_ctx handler_ctx; + +#include "base.h" +#include "array.h" +#include "buffer.h" +#include "log.h" +#include "status_counter.h" + +/** + * + * socket proxy (with optional buffering) + * + */ + +SETDEFAULTS_FUNC(mod_sockproxy_set_defaults) { + plugin_data *p = p_d; + data_unset *du; + size_t i = 0; + + config_values_t cv[] = { + { "sockproxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ + { "sockproxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ + { "sockproxy.balance", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } + }; + + p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *)); + force_assert(p->config_storage); + + for (i = 0; i < srv->config_context->used; i++) { + data_config const* config = (data_config const*)srv->config_context->data[i]; + plugin_config *s; + + s = calloc(1, sizeof(plugin_config)); + force_assert(s); + s->exts = NULL; + s->exts_auth = NULL; + s->exts_resp = NULL; + s->debug = 0; + + cv[0].destination = NULL; /* T_CONFIG_LOCAL */ + cv[1].destination = &(s->debug); + cv[2].destination = NULL; /* T_CONFIG_LOCAL */ + + p->config_storage[i] = s; + + if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) { + return HANDLER_ERROR; + } + + du = array_get_element(config->value, "sockproxy.server"); + if (!gw_set_defaults_backend(srv, (gw_plugin_data *)p, du, i, 0)) { + return HANDLER_ERROR; + } + + du = array_get_element(config->value, "sockproxy.balance"); + if (!gw_set_defaults_balance(srv, s, du)) { + return HANDLER_ERROR; + } + + /* disable check-local for all exts (default enabled) */ + if (s->exts) { /*(check after gw_set_defaults_backend())*/ + for (size_t j = 0; j < s->exts->used; ++j) { + gw_extension *ex = s->exts->exts[j]; + for (size_t n = 0; n < ex->used; ++n) { + ex->hosts[n]->check_local = 0; + } + } + } + } + + return HANDLER_GO_ON; +} + + +static handler_t sockproxy_create_env_connect(server *srv, handler_ctx *hctx) { + connection *con = hctx->remote_conn; + con->file_started = 1; + gw_set_transparent(srv, hctx); + http_response_upgrade_read_body_unknown(srv, con); + + status_counter_inc(srv, CONST_STR_LEN("sockproxy.requests")); + return HANDLER_GO_ON; +} + + +#define PATCH(x) \ + p->conf.x = s->x; +static int mod_sockproxy_patch_connection(server *srv, connection *con, plugin_data *p) { + size_t i, j; + plugin_config *s = p->config_storage[0]; + + PATCH(exts); + PATCH(exts_auth); + PATCH(exts_resp); + PATCH(debug); + PATCH(ext_mapping); + PATCH(balance); + + /* skip the first, the global context */ + for (i = 1; i < srv->config_context->used; i++) { + data_config *dc = (data_config *)srv->config_context->data[i]; + s = p->config_storage[i]; + + /* condition didn't match */ + if (!config_check_cond(srv, con, dc)) continue; + + /* merge config */ + for (j = 0; j < dc->value->used; j++) { + data_unset *du = dc->value->data[j]; + + if (buffer_is_equal_string(du->key, CONST_STR_LEN("sockproxy.server"))) { + PATCH(exts); + PATCH(exts_auth); + PATCH(exts_resp); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("sockproxy.debug"))) { + PATCH(debug); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("sockproxy.balance"))) { + PATCH(balance); + } + } + } + + return 0; +} +#undef PATCH + +static handler_t mod_sockproxy_connection_accept(server *srv, connection *con, void *p_d) { + plugin_data *p = p_d; + handler_t rc; + + if (con->mode != DIRECT) return HANDLER_GO_ON; + + mod_sockproxy_patch_connection(srv, con, p); + if (NULL == p->conf.exts) return HANDLER_GO_ON; + + /*(fake con->uri.path for matching purposes in gw_check_extension())*/ + buffer_copy_string_len(con->uri.path, CONST_STR_LEN("/")); + + rc = gw_check_extension(srv, con, p, 1, 0); + if (HANDLER_GO_ON != rc) return rc; + + if (con->mode == p->id) { + handler_ctx *hctx = con->plugin_ctx[p->id]; + hctx->opts.backend = BACKEND_PROXY; + hctx->create_env = sockproxy_create_env_connect; + hctx->response = buffer_init(); + con->http_status = -1; /*(skip HTTP processing)*/ + } + + return HANDLER_GO_ON; +} + + +int mod_sockproxy_plugin_init(plugin *p); +int mod_sockproxy_plugin_init(plugin *p) { + p->version = LIGHTTPD_VERSION_ID; + p->name = buffer_init_string("sockproxy"); + + p->init = gw_init; + p->cleanup = gw_free; + p->set_defaults = mod_sockproxy_set_defaults; + p->connection_reset = gw_connection_reset; + p->handle_connection_accept= mod_sockproxy_connection_accept; + p->handle_subrequest = gw_handle_subrequest; + p->handle_trigger = gw_handle_trigger; + p->handle_waitpid = gw_handle_waitpid_cb; + + p->data = NULL; + + return 0; +}