diff --git a/docs/manual/mod/mod_lua.html.en.utf8 b/docs/manual/mod/mod_lua.html.en.utf8
index 7e2d4becc55..33e8b8eed68 100644
--- a/docs/manual/mod/mod_lua.html.en.utf8
+++ b/docs/manual/mod/mod_lua.html.en.utf8
@@ -517,7 +517,19 @@ end
is_https |
boolean |
no |
- Whether or not this request is done via HTTPS |
+ Whether or not this request is done via HTTPS (alias to remote_is_https) |
+
+
+ remote_is_https |
+ boolean |
+ no |
+ Whether or not this request is done via HTTPS locally or on frontend |
+
+
+ local_is_https |
+ boolean |
+ no |
+ Whether or not the local connection is done via HTTPS |
is_initial_req |
diff --git a/docs/manual/mod/mod_lua.xml b/docs/manual/mod/mod_lua.xml
index aecbca3ed9e..28a53870f3a 100644
--- a/docs/manual/mod/mod_lua.xml
+++ b/docs/manual/mod/mod_lua.xml
@@ -484,7 +484,19 @@ end
is_https |
boolean |
no |
- Whether or not this request is done via HTTPS |
+ Whether or not this request is done via HTTPS (alias to remote_is_https) |
+
+
+ remote_is_https |
+ boolean |
+ no |
+ Whether or not this request is done via HTTPS locally or on frontend |
+
+
+ local_is_https |
+ boolean |
+ no |
+ Whether or not the local connection is done via HTTPS |
is_initial_req |
diff --git a/include/ap_mmn.h b/include/ap_mmn.h
index ccd504d8e82..07bc9724c10 100644
--- a/include/ap_mmn.h
+++ b/include/ap_mmn.h
@@ -737,6 +737,7 @@
* 20211221.29 (2.5.1-dev) Add ap_set_time_process_request() to scoreboard.h
* 20211221.30 (2.5.1-dev) Add ap_stat_check() to httpd.h
* 20211221.31 (2.5.1-dev) Add ap_*_timingsafe() to httpd.h
+ * 20211221.32 (2.5.1-dev) Add ap_remote_is_ssl() and hooks
*/
#define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
@@ -744,7 +745,7 @@
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20211221
#endif
-#define MODULE_MAGIC_NUMBER_MINOR 31 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 32 /* 0...n */
/**
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
diff --git a/include/http_request.h b/include/http_request.h
index 55e61ae2416..3cd82be0790 100644
--- a/include/http_request.h
+++ b/include/http_request.h
@@ -622,6 +622,25 @@ AP_DECLARE_HOOK(int,force_authn,(request_rec *r))
*/
AP_DECLARE_HOOK(apr_status_t,dirwalk_stat,(apr_finfo_t *finfo, request_rec *r, apr_int32_t wanted))
+/**
+ * This hook allows modules that virtualize SSL state (i.e. mod_remoteip)
+ * based on the data from remote frontend to register their inquiry function
+ * for checking if a remote frontend connection is using SSL for the request.
+ * @param r The current request
+ * @return OK iff the frontend connection is using SSL, DONE if not,
+ * DECLINED iff the state is undefined (let later modules decide).
+ * @ingroup hooks
+ */
+AP_DECLARE_HOOK(int,remote_is_ssl,(request_rec *r))
+
+/**
+ * Return != 0 iff the frontend connection for the request is encrypted with SSL.
+ * If there is no data from the hook (DECLINED), falls back to ap_ssl_conn_is_ssl()
+ * and so corresponds to the local connection security state (we are the frontend).
+ * @param r The current request
+ */
+AP_DECLARE(int) ap_remote_is_ssl(request_rec *r);
+
AP_DECLARE(int) ap_location_walk(request_rec *r);
AP_DECLARE(int) ap_directory_walk(request_rec *r);
AP_DECLARE(int) ap_file_walk(request_rec *r);
diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c
index 587b690c6fa..3acb68a06b4 100644
--- a/modules/lua/lua_request.c
+++ b/modules/lua/lua_request.c
@@ -754,6 +754,11 @@ static int req_ssl_is_https_field(request_rec *r)
return ap_lua_ssl_is_https(r->connection);
}
+static int req_remote_is_https_field(request_rec *r)
+{
+ return ap_lua_remote_is_https(r);
+}
+
static int req_ap_get_server_port(request_rec *r)
{
return (int) ap_get_server_port(r);
@@ -2782,7 +2787,11 @@ void ap_lua_load_request_lmodule(lua_State *L, apr_pool_t *p)
apr_hash_set(dispatch, "ssl_var_lookup", APR_HASH_KEY_STRING,
makefun(&req_ssl_var_lookup, APL_REQ_FUNTYPE_LUACFUN, p));
apr_hash_set(dispatch, "is_https", APR_HASH_KEY_STRING,
+ makefun(&req_remote_is_https_field, APL_REQ_FUNTYPE_BOOLEAN, p));
+ apr_hash_set(dispatch, "local_is_https", APR_HASH_KEY_STRING,
makefun(&req_ssl_is_https_field, APL_REQ_FUNTYPE_BOOLEAN, p));
+ apr_hash_set(dispatch, "remote_is_https", APR_HASH_KEY_STRING,
+ makefun(&req_remote_is_https_field, APL_REQ_FUNTYPE_BOOLEAN, p));
apr_hash_set(dispatch, "assbackwards", APR_HASH_KEY_STRING,
makefun(&req_assbackwards_field, APL_REQ_FUNTYPE_BOOLEAN, p));
apr_hash_set(dispatch, "status", APR_HASH_KEY_STRING,
diff --git a/modules/lua/mod_lua.c b/modules/lua/mod_lua.c
index c2c751a92ae..5b724bf1eb8 100644
--- a/modules/lua/mod_lua.c
+++ b/modules/lua/mod_lua.c
@@ -1715,6 +1715,11 @@ int ap_lua_ssl_is_https(conn_rec *c)
return ap_ssl_conn_is_ssl(c);
}
+int ap_lua_remote_is_https(request_rec *r)
+{
+ return ap_remote_is_ssl(r);
+}
+
/*******************************/
static const char *lua_authz_parse(cmd_parms *cmd, const char *require_line,
diff --git a/modules/lua/mod_lua.h b/modules/lua/mod_lua.h
index 33807fbdb56..c3738f878af 100644
--- a/modules/lua/mod_lua.h
+++ b/modules/lua/mod_lua.h
@@ -183,5 +183,6 @@ const char *ap_lua_ssl_val(apr_pool_t *p, server_rec *s, conn_rec *c,
request_rec *r, const char *var);
int ap_lua_ssl_is_https(conn_rec *c);
+int ap_lua_remote_is_https(request_rec *r);
#endif /* !_MOD_LUA_H_ */
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index c89b2adc786..b5eee48f76c 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -2086,7 +2086,7 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx)
case 5:
if (!strcmp(var, "HTTPS")) {
- int flag = ap_ssl_conn_is_ssl(r->connection);
+ int flag = ap_remote_is_ssl(r);
return apr_pstrdup(r->pool, flag ? "on" : "off");
}
break;
@@ -2195,6 +2195,13 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx)
}
break;
+ case 'H':
+ if (!strcmp(var, "HTTPS_LOCAL")) {
+ int flag = ap_ssl_conn_is_ssl(r->connection);
+ return apr_pstrdup(r->pool, flag ? "on" : "off");
+ }
+ break;
+
case 'I':
if (!strcmp(var, "API_VERSION")) {
return apr_psprintf(r->pool, "%d:%d",
@@ -2244,6 +2251,13 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx)
case 12:
switch (var[3]) {
+ case 'H':
+ if (!strcmp(var, "HTTPS_REMOTE")) {
+ int flag = ap_remote_is_ssl(r);
+ return apr_pstrdup(r->pool, flag ? "on" : "off");
+ }
+ break;
+
case 'I':
if (!strcmp(var, "SCRIPT_GROUP")) {
result = "";
diff --git a/modules/metadata/mod_remoteip.c b/modules/metadata/mod_remoteip.c
index 805c6543ea5..c6ede9ef1da 100644
--- a/modules/metadata/mod_remoteip.c
+++ b/modules/metadata/mod_remoteip.c
@@ -25,6 +25,9 @@
#include "http_connection.h"
#include "http_protocol.h"
#include "http_log.h"
+#include "http_request.h"
+#include "http_ssl.h"
+#include "http_vhost.h"
#include "http_main.h"
#include "apr_strings.h"
#include "apr_lib.h"
@@ -61,6 +64,13 @@ typedef struct {
*/
apr_array_header_t *proxymatch_ip;
+ const char *host_header_name;
+ const char *port_header_name;
+ const char *proto_header_name;
+ const char *proto_https_enable;
+ int proto_https_enable_any;
+ int forbid_direct;
+
remoteip_addr_info *proxy_protocol_enabled;
remoteip_addr_info *proxy_protocol_disabled;
@@ -141,10 +151,18 @@ typedef struct {
configurable parameters
*/
typedef struct {
+ /** Indicates presence of client address info in the structure **/
+ int has_client_addr;
/** The parsed client address in native format */
apr_sockaddr_t *client_addr;
/** Character representation of the client */
char *client_ip;
+ /** Remote port */
+ int remote_port;
+ /** Indicates presence of SSL flag */
+ int has_remote_is_ssl;
+ /** Remote SSL flag */
+ int remote_is_ssl;
} remoteip_conn_config_t;
typedef enum { HDR_DONE, HDR_ERROR, HDR_NEED_MORE } remoteip_parse_status_t;
@@ -157,6 +175,11 @@ static void *create_remoteip_server_config(apr_pool_t *p, server_rec *s)
* config->proxies_header_name = NULL;
* config->proxy_protocol_enabled = NULL;
* config->proxy_protocol_disabled = NULL;
+ * config->host_header_name = NULL;
+ * config->port_header_name = NULL;
+ * config->proto_header_name = NULL;
+ * config->proto_https_enable = NULL;
+ * config->proto_https_enable_any = 0;
*/
config->pool = p;
return config;
@@ -179,6 +202,23 @@ static void *merge_remoteip_server_config(apr_pool_t *p, void *globalv,
config->proxymatch_ip = server->proxymatch_ip
? server->proxymatch_ip
: global->proxymatch_ip;
+ config->host_header_name = server->host_header_name
+ ? server->host_header_name
+ : global->host_header_name;
+ config->port_header_name = server->port_header_name
+ ? server->port_header_name
+ : global->port_header_name;
+ config->proto_header_name = server->proto_header_name
+ ? server->proto_header_name
+ : global->proto_header_name;
+ config->proto_https_enable = server->proto_https_enable
+ ? server->proto_https_enable
+ : global->proto_https_enable;
+ config->proto_https_enable_any = (config->proto_https_enable && !strcmp("*", config->proto_https_enable));
+ config->forbid_direct = server->forbid_direct
+ ? server->forbid_direct
+ : global->forbid_direct;
+
return config;
}
@@ -540,15 +580,21 @@ static int remoteip_modify_request(request_rec *r)
*/
void *internal = NULL;
- /* No header defined or results from our input filter */
- if (!config->header_name && !conn_config) {
+ /* Avoid doing any work on internal subrequests or redirects */
+ if (r->main || r->prev) {
+ return DECLINED;
+ }
+
+ /* No headers defined or results from our input filter */
+ if (!conn_config && !config->header_name
+ && !config->host_header_name && !config->port_header_name
+ && !config->proto_header_name && !config->forbid_direct) {
return DECLINED;
}
-
- /* Easy parsing case - just position the data we already have from PROXY
- protocol handling allowing it to take precedence and return
- */
- if (conn_config) {
+
+ /* Position the remote IP data we may already have from PROXY protocol handling
+ */
+ if (conn_config && conn_config->has_client_addr) {
if (!conn_config->client_addr) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(03496)
"RemoteIPProxyProtocol data is missing, but required! Aborting request.");
@@ -560,7 +606,8 @@ static int remoteip_modify_request(request_rec *r)
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
"Using %s as client's IP from PROXY protocol", r->useragent_ip);
- return OK;
+ /* We do not return here as we may still have specific remote parameters headers set by proxy
+ */
}
if (config->proxymatch_ip) {
@@ -571,14 +618,117 @@ static int remoteip_modify_request(request_rec *r)
internal = (void *) 1;
}
+ temp_sa = r->useragent_addr ? r->useragent_addr : c->client_addr;
+
+ if (internal && (config->host_header_name || config->port_header_name || config->proto_header_name || config->forbid_direct)) {
+ /* The trusted proxy (or list of) is configured, honor the option to forbid direct connections (allowing only trusted internal proxies)
+ Also, if the connecting host is trusted internal proxy and some request modification headers are set, we honor these headers there
+ */
+ int i;
+ void *first_internal = NULL;
+ remoteip_proxymatch_t *match;
+ match = (remoteip_proxymatch_t *)config->proxymatch_ip->elts;
+ for (i = 0; i < config->proxymatch_ip->nelts; ++i) {
+ if (apr_ipsubnet_test(match[i].ip, temp_sa)) {
+ first_internal = match[i].internal;
+ break;
+ }
+ }
+ if ((i && i >= config->proxymatch_ip->nelts) || !first_internal) {
+ if (config->forbid_direct) {
+ /* Whoops, trusted internal proxy was not detected and direct requests are forbidden, deny the request
+ */
+ return HTTP_FORBIDDEN;
+ }
+ } else {
+ /* Internal trusted proxy is connecting, perform request modification if any options for it are set
+ */
+ char *val;
+
+ /* Remote host option, applied directly to the request host header
+ */
+ if (config->host_header_name) {
+ const char *host;
+ if ( (host = apr_table_get(r->headers_in, config->host_header_name)) ) {
+ /* Propagate host header value from the header set by proxy and update virtual host chosen (the primary purpose of it)
+ */
+ apr_array_header_t *hdrs = apr_array_make(r->pool, 0, sizeof(char*));
+ while (*host && (val = ap_get_token(r->pool, &host, 1))) {
+ APR_ARRAY_PUSH(hdrs, char *) = apr_pstrdup(r->pool, val);
+ if (*host != '\0')
+ ++host;
+ }
+ apr_table_setn(r->headers_in, "Host", apr_pstrdup(r->pool, APR_ARRAY_IDX(hdrs, hdrs->nelts - 1, char *)));
+ r->hostname = apr_pstrdup(r->pool, APR_ARRAY_IDX(hdrs, hdrs->nelts - 1, char *));
+ ap_update_vhost_from_headers(r);
+ }
+ }
+
+ /* Remote port option, due to the transient nature of subrequests we have to store the port number for entire connection for ap_default_port() hook
+ */
+ if (config->port_header_name) {
+ const char *port;
+
+ if (!conn_config) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO()
+ "Remote IP per-connection data is missing, but required for RemotePortHeader! Aborting request.");
+ return HTTP_BAD_REQUEST;
+ }
+
+ if ( (port = apr_table_get(r->headers_in, config->port_header_name) )) {
+ r->parsed_uri.port = r->server->port;
+ conn_config->remote_port = atoi(port);
+ } else {
+ /* Subsequent requests inside a single connection need to have the port number reset if they do not have the header set
+ */
+ conn_config->remote_port = 0;
+ }
+ }
+
+ /* Remote HTTPS protocol option, due to transient nature of subrequests we have to store the flag for entire connection for ap_remote_is_ssl() and fixup hooks
+ */
+ if (config->proto_header_name) {
+ const char *proto;
+
+ if (!conn_config) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO()
+ "Remote IP per-connection data is missing, but required for RemoteProtoHeader! Aborting request.");
+ return HTTP_BAD_REQUEST;
+ }
+
+ /* Indicate we have set the remote_is_ssl flag
+ */
+ conn_config->has_remote_is_ssl = 1;
+
+ if ( (proto = apr_table_get(r->headers_in, config->proto_header_name)) ) {
+ /* Check HTTPS protocol ID, defaulting to 'https' if not set, proto_https_enable_any is set in config option/merge for empty string or '*'
+ */
+ if (config->proto_https_enable_any || !ap_cstr_casecmp(proto, config->proto_https_enable ? config->proto_https_enable : "https")) {
+ conn_config->remote_is_ssl = 1;
+ } else {
+ /* Subsequent requests inside a single connection need to have the flag reset if they do not have the content match
+ */
+ conn_config->remote_is_ssl = 0;
+ }
+ } else {
+ /* Subsequent requests inside a single connection need to have the flag reset if they do not have the header found
+ */
+ conn_config->remote_is_ssl = 0;
+ }
+ }
+ }
+ }
+
+ /* No need to proceed further if we have no remote IP header set
+ */
+ if (!config->header_name) return OK;
+
remote = (char *) apr_table_get(r->headers_in, config->header_name);
if (!remote) {
return OK;
}
remote = apr_pstrdup(r->pool, remote);
- temp_sa = r->useragent_addr ? r->useragent_addr : c->client_addr;
-
while (remote) {
/* verify user agent IP against the trusted proxy list
@@ -749,6 +899,104 @@ static int remoteip_modify_request(request_rec *r)
return OK;
}
+static int remoteip_hook_remote_is_ssl(request_rec *r)
+{
+ remoteip_conn_config_t *conn_config = (remoteip_conn_config_t *)
+ ap_get_module_config(r->connection->conn_config, &remoteip_module);
+
+ if (conn_config && conn_config->has_remote_is_ssl) {
+ return conn_config->remote_is_ssl ? OK : DONE;
+ }
+
+ return DECLINED;
+}
+
+static const char *remoteip_hook_http_scheme(const request_rec *r)
+{
+ remoteip_conn_config_t *conn_config = (remoteip_conn_config_t *)
+ ap_get_module_config(r->connection->conn_config, &remoteip_module);
+
+ if (!conn_config) {
+ return NULL;
+ }
+
+ if (!conn_config->has_remote_is_ssl) {
+ return NULL;
+ }
+
+ return (conn_config->remote_is_ssl) ? "https" : "http";
+}
+
+static apr_port_t remoteip_hook_default_port(const request_rec *r)
+{
+ remoteip_conn_config_t *conn_config = (remoteip_conn_config_t *)
+ ap_get_module_config(r->connection->conn_config, &remoteip_module);
+
+ if (!conn_config) {
+ return 0;
+ }
+
+ return conn_config->remote_port;
+}
+
+static int remoteip_hook_fixups(request_rec *r)
+{
+ remoteip_conn_config_t *conn_config = (remoteip_conn_config_t *)
+ ap_get_module_config(r->connection->conn_config, &remoteip_module);
+
+ if (!conn_config) {
+ return DECLINED;
+ }
+
+ if (!conn_config->has_remote_is_ssl) {
+ return DECLINED;
+ }
+
+ if (conn_config->remote_is_ssl) {
+ apr_table_setn(r->subprocess_env, "HTTPS", "on");
+ } else {
+ apr_table_unset(r->subprocess_env, "HTTPS");
+ }
+
+ return DECLINED;
+}
+
+static const char *host_header_name_set(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ remoteip_config_t *config = ap_get_module_config(cmd->server->module_config, &remoteip_module);
+ config->host_header_name = arg;
+ return NULL;
+}
+
+static const char *port_header_name_set(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ remoteip_config_t *config = ap_get_module_config(cmd->server->module_config, &remoteip_module);
+ config->port_header_name = arg;
+ return NULL;
+}
+
+static const char *proto_header_name_set(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ remoteip_config_t *config = ap_get_module_config(cmd->server->module_config, &remoteip_module);
+ config->proto_header_name = arg;
+ return NULL;
+}
+
+static const char *proto_https_enable_set(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ remoteip_config_t *config = ap_get_module_config(cmd->server->module_config, &remoteip_module);
+ config->proto_https_enable = arg;
+ config->proto_https_enable_any = (config->proto_https_enable && !strcmp("*", config->proto_https_enable));
+ return NULL;
+}
+
+static const char *forbid_direct_set(cmd_parms *cmd, void *dummy, int flag)
+{
+ remoteip_config_t *config = ap_get_module_config(cmd->server->module_config, &remoteip_module);
+ config->forbid_direct = flag;
+ return NULL;
+}
+
static int remoteip_is_server_port(apr_port_t port)
{
ap_listen_rec *lr;
@@ -868,35 +1116,22 @@ static remoteip_parse_status_t remoteip_process_v1_header(conn_rec *c,
conn_conf->client_ip = apr_pstrdup(c->pool, host);
+ conn_conf->has_client_addr = 1;
+
return HDR_DONE;
}
-/** Add our filter to the connection if it is requested
+/* Add our filter to the connection if it is requested
*/
-static int remoteip_hook_pre_connection(conn_rec *c, void *csd)
+static int remoteip_pre_check_for_proxy_protocol(conn_rec *c, remoteip_config_t *conf)
{
- remoteip_config_t *conf;
- remoteip_conn_config_t *conn_conf;
int i;
- /* Establish master config in slave connections, so that request processing
- * finds it. */
- if (c->master != NULL) {
- conn_conf = ap_get_module_config(c->master->conn_config, &remoteip_module);
- if (conn_conf) {
- ap_set_module_config(c->conn_config, &remoteip_module, conn_conf);
- }
- return DECLINED;
- }
-
- conf = ap_get_module_config(ap_server_conf->module_config,
- &remoteip_module);
-
/* check if we're enabled for this connection */
if (!remoteip_addr_in_list(conf->proxy_protocol_enabled, c->local_addr)
|| remoteip_addr_in_list(conf->proxy_protocol_disabled, c->local_addr)) {
- return DECLINED;
+ return 0;
}
/* We are enabled for this IP/port, but check that we aren't
@@ -905,27 +1140,70 @@ static int remoteip_hook_pre_connection(conn_rec *c, void *csd)
apr_ipsubnet_t *ip = ((apr_ipsubnet_t**)conf->disabled_subnets->elts)[i];
if (ip && apr_ipsubnet_test(ip, c->client_addr))
- return DECLINED;
+ return 0;
}
/* mod_proxy creates outgoing connections - we don't want those */
if (!remoteip_is_server_port(c->local_addr->port)) {
- return DECLINED;
+ return 0;
}
/* add our filter */
if (!ap_add_input_filter_handle(remoteip_filter, NULL, NULL, c)) {
/* XXX: Shouldn't this WARN in log? */
- return DECLINED;
+ return 0;
}
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03503)
"RemoteIPProxyProtocol: enabled on connection to %s:%hu",
c->local_ip, c->local_addr->port);
- /* this holds the resolved proxy info for this connection */
- conn_conf = apr_pcalloc(c->pool, sizeof(*conn_conf));
+ return 1;
+}
+
+/* Pre-connection check for PROXY protocol and other conditions requiring
+ * per-connection configuration to be created
+ */
+static int remoteip_hook_pre_connection(conn_rec *c, void *csd)
+{
+ remoteip_config_t *conf;
+ remoteip_conn_config_t *conn_conf;
+ int need_conf;
+
+ /* Establish master config in slave connections, so that request processing
+ * finds it. */
+ if (c->master != NULL) {
+ conn_conf = ap_get_module_config(c->master->conn_config, &remoteip_module);
+ if (conn_conf) {
+ ap_set_module_config(c->conn_config, &remoteip_module, conn_conf);
+ }
+ return DECLINED;
+ }
+
+ conf = ap_get_module_config(ap_server_conf->module_config,
+ &remoteip_module);
+ /* Check if we have PROXY protocol enabled, this goes first as it needs to install the filter
+ */
+ if (remoteip_pre_check_for_proxy_protocol(c, conf)) {
+ need_conf = 1;
+ }
+
+ /* Check if we need to store remote port or SSL information, not joined with previous check for clarity
+ */
+ if (conf->port_header_name || conf->proto_header_name) {
+ need_conf = 1;
+ }
+
+ /* Bail out if we do not need the configuration structure
+ */
+ if (!need_conf) {
+ return DECLINED;
+ }
+
+ /* This holds the resolved proxy info and/or remote SSL info for this connection
+ */
+ conn_conf = apr_pcalloc(c->pool, sizeof(*conn_conf));
ap_set_module_config(c->conn_config, &remoteip_module, conn_conf);
return OK;
@@ -1036,6 +1314,8 @@ static remoteip_parse_status_t remoteip_process_v2_header(conn_rec *c,
return HDR_ERROR;
}
+ conn_conf->has_client_addr = 1;
+
return HDR_DONE;
}
@@ -1242,7 +1522,7 @@ static const command_rec remoteip_cmds[] =
"e.g. X-Forwarded-By; if not given then do not record"),
AP_INIT_ITERATE("RemoteIPTrustedProxy", proxies_set, 0, RSRC_CONF,
"Specifies one or more proxies which are trusted "
- "to present IP headers"),
+ "to present IP and request modification headers"),
AP_INIT_ITERATE("RemoteIPInternalProxy", proxies_set, (void*)1, RSRC_CONF,
"Specifies one or more internal (transparent) proxies "
"which are trusted to present IP headers"),
@@ -1259,6 +1539,25 @@ static const command_rec remoteip_cmds[] =
AP_INIT_TAKE_ARGV("RemoteIPProxyProtocolExceptions",
remoteip_disable_networks, NULL, RSRC_CONF, "Disable PROXY "
"protocol handling for this list of networks in CIDR format"),
+ AP_INIT_TAKE1("RemoteHostHeader", host_header_name_set, NULL, RSRC_CONF,
+ "Specifies a request header to trust as the original Host header, "
+ "e.g. X-Forwarded-Host, valid only if direct client is internal proxy, "
+ "defaults to disabled"),
+ AP_INIT_TAKE1("RemotePortHeader", port_header_name_set, NULL, RSRC_CONF,
+ "Specifies a request header to trust as the original Port header, "
+ "e.g. X-Forwarded-Port, valid only if direct client is internal proxy, "
+ "defaults to disabled"),
+ AP_INIT_TAKE1("RemoteProtoHeader", proto_header_name_set, NULL, RSRC_CONF,
+ "Specifies a request header to trust as the original protocol header, "
+ "e.g. X-Forwarded-Proto, valid only if direct client is internal proxy, "
+ "defaults to disabled"),
+ AP_INIT_TAKE1("RemoteHTTPSEnableProto", proto_https_enable_set, NULL, RSRC_CONF,
+ "Specifies a value in the header specified by RemoteProtoHeader that "
+ "is required to set HTTPS flag enabled, setting this to '*' will enable "
+ "HTTPS flag just on header presence, disregarding the header value, the "
+ "comparison is case-insensitive, defaults to 'https'"),
+ AP_INIT_FLAG("RemoteAllowOnlyInternalProxies", forbid_direct_set, NULL, RSRC_CONF,
+ "Deny access from any hosts besides trusted internal proxies"),
{ NULL }
};
@@ -1266,13 +1565,17 @@ static void register_hooks(apr_pool_t *p)
{
/* mod_ssl is CONNECTION + 5, so we want something higher (earlier);
* mod_reqtimeout is CONNECTION + 8, so we want something lower (later) */
- remoteip_filter =
+ remoteip_filter =
ap_register_input_filter("REMOTEIP_INPUT", remoteip_input_filter, NULL,
AP_FTYPE_CONNECTION + 7);
ap_hook_post_config(remoteip_hook_post_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_pre_connection(remoteip_hook_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_read_request(remoteip_modify_request, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_remote_is_ssl(remoteip_hook_remote_is_ssl, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_http_scheme(remoteip_hook_http_scheme, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_default_port(remoteip_hook_default_port, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_fixups(remoteip_hook_fixups, NULL, NULL, APR_HOOK_LAST);
}
AP_DECLARE_MODULE(remoteip) = {
diff --git a/server/request.c b/server/request.c
index 791d1cea6b9..a3210f913d4 100644
--- a/server/request.c
+++ b/server/request.c
@@ -41,6 +41,7 @@
#include "http_protocol.h"
#include "http_log.h"
#include "http_main.h"
+#include "http_ssl.h"
#include "util_filter.h"
#include "util_charset.h"
#include "util_script.h"
@@ -74,6 +75,7 @@ APR_HOOK_STRUCT(
APR_HOOK_LINK(dirwalk_stat)
APR_HOOK_LINK(force_authn)
APR_HOOK_LINK(token_checker)
+ APR_HOOK_LINK(remote_is_ssl)
)
AP_IMPLEMENT_HOOK_RUN_FIRST(int,pre_translate_name,
@@ -106,6 +108,8 @@ AP_IMPLEMENT_HOOK_RUN_FIRST(int,force_authn,
(request_rec *r), (r), DECLINED)
AP_IMPLEMENT_HOOK_RUN_FIRST(int,token_checker,
(request_rec *r), (r), DECLINED)
+AP_IMPLEMENT_HOOK_RUN_FIRST(int, remote_is_ssl,
+ (request_rec *r), (r), DECLINED)
static int auth_internal_per_conf = 0;
static int auth_internal_per_conf_hooks = 0;
@@ -2603,3 +2607,12 @@ AP_DECLARE(int) ap_is_initial_req(request_rec *r)
&& (r->prev == NULL); /* otherwise, this is an internal redirect */
}
+/*
+ * Is remote frontend connection SSL? Hooks return OK if yes, DONE if no
+ * If hook sequence returns DECLINED, we fall back to ap_ssl_conn_is_ssl()
+*/
+AP_DECLARE(int) ap_remote_is_ssl(request_rec *r)
+{
+ int result = ap_run_remote_is_ssl(r);
+ return (result == DECLINED) ? ap_ssl_conn_is_ssl(r->connection) : (result == OK);
+}
diff --git a/server/util_expr_eval.c b/server/util_expr_eval.c
index 82f3288a2c1..8bb9e248dfa 100644
--- a/server/util_expr_eval.c
+++ b/server/util_expr_eval.c
@@ -1696,7 +1696,7 @@ APR_DECLARE_OPTIONAL_FN(int, http2_is_h2, (conn_rec *));
static APR_OPTIONAL_FN_TYPE(http2_is_h2) *is_http2 = NULL;
static const char *const conn_var_names[] = {
- "HTTPS", /* 0 */
+ "HTTPS_LOCAL", /* 0 */
"IPV6", /* 1 */
"CONN_LOG_ID", /* 2 */
"CONN_REMOTE_ADDR", /* 3 */
@@ -1779,6 +1779,8 @@ static const char *const request_var_names[] = {
"SERVER_PROTOCOL_VERSION_MAJOR", /* 30 */
"SERVER_PROTOCOL_VERSION_MINOR", /* 31 */
"REMOTE_PORT", /* 32 */
+ "HTTPS", /* 33 */
+ "HTTPS_REMOTE", /* 34 */
NULL
};
@@ -1890,6 +1892,12 @@ static const char *request_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
return apr_psprintf(ctx->p, "%d", HTTP_VERSION_MINOR(r->proto_num));
case 32:
return apr_psprintf(ctx->p, "%u", ctx->c->client_addr->port);
+ case 33:
+ case 34:
+ if (ap_remote_is_ssl(r))
+ return "on";
+ else
+ return "off";
default:
ap_assert(0);
return NULL;