ASF Bugzilla – Attachment 34781 Details for
Bug 59829
Detect HTTPS marker from reverse proxy
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Allow multiple SSL ports
remoteip.patch (text/plain), 21.69 KB, created by
Yordan Gigov
on 2017-02-27 11:43:21 UTC
(
hide
)
Description:
Allow multiple SSL ports
Filename:
MIME Type:
Creator:
Yordan Gigov
Created:
2017-02-27 11:43:21 UTC
Size:
21.69 KB
patch
obsolete
>diff --git a/include/http_protocol.h b/include/http_protocol.h >index 63c3b0c..512241e 100644 >--- a/include/http_protocol.h >+++ b/include/http_protocol.h >@@ -690,6 +690,19 @@ AP_DECLARE(const char *) ap_method_name_of(apr_pool_t *p, int methnum); > AP_DECLARE_HOOK(void,pre_read_request,(request_rec *r, conn_rec *c)) > > /* >+ * post_headers_parsed --- run right before ap_update_vhost_from_headers(), >+ * and not run during any subrequests. >+ */ >+/** >+ * This hook allows modules to affect the request or connection immediately after >+ * request headers are parsed and verified, but before the VirtualHost has been >+ * resolved. >+ * @param r The current request >+ * @return OK or DECLINED >+ */ >+AP_DECLARE_HOOK(int,post_headers_parsed,(request_rec *r)) >+ >+/* > * post_read_request --- run right after read_request or internal_redirect, > * and not run during any subrequests. > */ >diff --git a/modules/http2/h2_request.c b/modules/http2/h2_request.c >index 25dc971..09c9826 100644 >--- a/modules/http2/h2_request.c >+++ b/modules/http2/h2_request.c >@@ -239,6 +239,18 @@ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c) > * otherwise we get complains about port numbers. > */ > r->hostname = NULL; >+ >+ if (access_status = ap_run_post_headers_parsed(r)) { >+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, >+ "post_headers_parsed hooks returned failure"); >+ ap_die(access_status, r); >+ ap_update_child_status(c->sbh, SERVER_BUSY_LOG, r); >+ ap_run_log_transaction(r); >+ r = NULL; >+ goto traceout; >+ } >+ >+ > ap_update_vhost_from_headers(r); > > /* we may have switched to another server */ >diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c >index 67d692a..9209271 100644 >--- a/modules/mappers/mod_rewrite.c >+++ b/modules/mappers/mod_rewrite.c >@@ -425,7 +425,6 @@ static const char *rewritemap_mutex_type = "rewrite-map"; > > /* Optional functions imported from mod_ssl when loaded: */ > static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *rewrite_ssl_lookup = NULL; >-static APR_OPTIONAL_FN_TYPE(ssl_is_https) *rewrite_is_https = NULL; > static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus); > > /* >@@ -1963,8 +1962,7 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx) > > case 5: > if (!strcmp(var, "HTTPS")) { >- int flag = rewrite_is_https && rewrite_is_https(r->connection); >- return apr_pstrdup(r->pool, flag ? "on" : "off"); >+ return apr_pstrdup(r->pool, !strcasecmp("https", ap_http_scheme(r)) ? "on" : "off"); > } > break; > >@@ -4527,7 +4525,6 @@ static int post_config(apr_pool_t *p, > } > > rewrite_ssl_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); >- rewrite_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); > > return OK; > } >diff --git a/modules/metadata/mod_remoteip.c b/modules/metadata/mod_remoteip.c >index 7969766..cbc9ca6 100644 >--- a/modules/metadata/mod_remoteip.c >+++ b/modules/metadata/mod_remoteip.c >@@ -23,9 +23,10 @@ > #include "httpd.h" > #include "http_config.h" > #include "http_connection.h" >-#include "http_protocol.h" > #include "http_log.h" > #include "http_main.h" >+#include "http_protocol.h" >+#include "http_request.h" > #include "apr_strings.h" > #include "apr_lib.h" > #define APR_WANT_BYTEFUNC >@@ -55,6 +56,14 @@ typedef struct { > * from the proxy-via IP header value list) > */ > const char *proxies_header_name; >+ /** A header that may indicate user is using a >+ * HTTPS connection to the reverse-proxy, and >+ * the value that it must match for it to do so. >+ */ >+ const char *secure_header_name; >+ const char *secure_header_value; >+ const char *server_port_header; >+ apr_array_header_t *secure_ports; > /** A list of trusted proxies, ideally configured > * with the most commonly encountered listed first > */ >@@ -150,6 +159,8 @@ typedef struct { > apr_sockaddr_t *client_addr; > /** Character representation of the client */ > char *client_ip; >+ /** The port on which the proxy server received the connection */ >+ unsigned short server_port; > /** Flag indicating that the PROXY header may be omitted on this > connection (do not abort if it is missing). */ > int proxy_protocol_optional; >@@ -191,6 +202,18 @@ static void *merge_remoteip_server_config(apr_pool_t *p, void *globalv, > config->pp_optional = server->pp_optional > ? server->pp_optional > : global->pp_optional; >+ config->secure_header_name = server->secure_header_name >+ ? server->secure_header_name >+ : global->secure_header_name; >+ config->secure_header_value = server->secure_header_value >+ ? server->secure_header_value >+ : global->secure_header_value; >+ config->server_port_header = server->server_port_header >+ ? server->server_port_header >+ : global->server_port_header; >+ config->secure_ports = server->secure_ports >+ ? server->secure_ports >+ : global->secure_ports; > return config; > } > >@@ -212,6 +235,63 @@ static const char *proxies_header_name_set(cmd_parms *cmd, void *dummy, > return NULL; > } > >+static const char *server_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); >+ if (!arg) >+ return "RemoteIPServerPortHeader requires header name"; >+ config->server_port_header = arg; >+ return NULL; >+} >+ >+static const char *secure_header_set(cmd_parms *cmd, void *dummy, >+ const char *name, const char *value) >+{ >+ remoteip_config_t *config = ap_get_module_config(cmd->server->module_config, >+ &remoteip_module); >+ if (!name || !value) >+ return "RemoteIPSecureHeader requires header name and valid value"; >+ >+ config->secure_header_name = name; >+ config->secure_header_value = value; >+ return NULL; >+} >+ >+static int parse_validate_port(const char *src, unsigned short *dst) >+{ >+ if (src) { >+ char *tail; >+ int intval; >+ intval = apr_strtoi64(src, &tail, 0); >+ if (errno == 0 && *tail == '\0' && intval > 0 && intval < 65536) { >+ *dst = (unsigned short) intval; >+ return 0; /* no error */ >+ } >+ return 2; /* not a number or invaid port range */ >+ } >+ return 1; /* null pointer */ >+} >+ >+static const char *secure_ports_set(cmd_parms *cmd, void *d, int argc, char *const argv[]) >+{ >+ unsigned short current_port; >+ unsigned short *current_ptr; >+ remoteip_config_t *config = ap_get_module_config(cmd->server->module_config, >+ &remoteip_module); >+ config->secure_ports = apr_array_make(cmd->pool, argc, sizeof(unsigned short)); >+ for (int i = 0; i < argc; i++) { >+ if (parse_validate_port(argv[i], ¤t_port)) >+ return apr_psprintf(cmd->pool, >+ "RemoteIPSSLPorts values must be integers between 0 and 65536. " >+ "'%s' is not a valid value.", argv[i]); >+ APR_ARRAY_PUSH(config->secure_ports, unsigned short) = current_port; >+ } >+ >+ return NULL; >+} >+ > /* Would be quite nice if APR exported this */ > /* apr:network_io/unix/sockaddr.c */ > static int looks_like_ip(const char *ipstr) >@@ -506,6 +586,11 @@ static int remoteip_modify_request(request_rec *r) > char *proxy_ips = NULL; > char *parse_remote; > char *eos; >+ char *secure = NULL; >+ char *inport = NULL; >+ char *proxy_note = NULL; >+ unsigned short parsed_port = 0; >+ unsigned short port_ptr; > unsigned char *addrbyte; > > /* If no RemoteIPInternalProxy, RemoteIPInternalProxyList, RemoteIPTrustedProxy >@@ -528,7 +613,7 @@ static int remoteip_modify_request(request_rec *r) > if (config->pp_optional) { > ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03495) > "RemoteIPProxyProtocol data is missing, but was optional. Allowing request."); >- return OK; >+ goto PROXY_OPTIONAL_NOTSENT; > } > else { > ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(03496) >@@ -539,12 +624,43 @@ static int remoteip_modify_request(request_rec *r) > > r->useragent_addr = conn_config->client_addr; > r->useragent_ip = conn_config->client_ip; >+ parsed_port = conn_config->server_port; >+ if (!config->secure_ports) { >+ /* RemoteIPSSLPorts is not set. */ >+ /* default port 443 when not set */ >+ secure = parsed_port == 443 ? "on" : NULL; >+ } >+ else if (config->secure_ports->nelts) { >+ /* RemoteIPSSLPorts is set and has elements. */ >+ for (int i = 0, nelts = config->secure_ports->nelts; i < nelts; ++i) { >+ port_ptr = APR_ARRAY_IDX(config->secure_ports, i, unsigned short); >+ if (port_ptr == parsed_port) { >+ secure = "on"; >+ break; >+ } >+ } >+ } >+ >+ if (secure) { >+ apr_table_setn(r->subprocess_env, "HTTPS", "on"); >+ proxy_note = apr_psprintf(r->pool, >+ "s:%u", >+ parsed_port); >+ } >+ else { >+ proxy_note = apr_psprintf(r->pool, >+ "i:%u", >+ parsed_port); >+ } >+ apr_table_setn(r->notes, "remoteip-data", proxy_note); > > ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, > "Using %s as client's IP from PROXY protocol", r->useragent_ip); > return OK; > } > >+ PROXY_OPTIONAL_NOTSENT: >+ > if (config->proxymatch_ip) { > /* This indicates that a RemoteIPInternalProxy, RemoteIPInternalProxyList, RemoteIPTrustedProxy > or RemoteIPTrustedProxyList directive is configured. >@@ -698,6 +814,64 @@ static int remoteip_modify_request(request_rec *r) > return OK; > } > >+ if (config->secure_header_name) { >+ secure = (char *) apr_table_get(r->headers_in, config->secure_header_name); >+ if (secure) { >+ /* Header is available. Unset even if no match. */ >+ apr_table_unset(r->headers_in, config->secure_header_name); >+ } >+ } >+ if (config->server_port_header) { >+ inport = (char *) apr_table_get(r->headers_in, config->server_port_header); >+ if (inport) { >+ /* Header is available. Unset even if no match. */ >+ apr_table_unset(r->headers_in, config->server_port_header); >+ } >+ } >+ >+ if (inport && parse_validate_port(inport, &parsed_port)) { >+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, >+ "Invalid port \"%s\" sent by server via \"%s\"", >+ inport, config->server_port_header); >+ parsed_port = 0; >+ } >+ >+ if (secure) { >+ /* User has set RemoteIPSecureHeader and the value */ >+ if (strcmp(secure, config->secure_header_value)) { >+ secure = NULL; >+ } >+ } >+ else { >+ secure = NULL; >+ } >+ if (inport && !config->secure_ports) { >+ /* User has set RemoteIPServerPortHeader and port is received, >+ but RemoteIPSSLPorts is not set. */ >+ /* default port 443 when not set */ >+ secure = parsed_port == 443 ? "on" : NULL; >+ } >+ else if (inport && config->secure_ports && config->secure_ports->nelts) { >+ /* User has set RemoteIPServerPortHeader and port is received, >+ RemoteIPSSLPorts is also set. */ >+ /* reset because if port settings mismatch, servers are misconfigured */ >+ secure = NULL; >+ if (parsed_port) { >+ for (int i = 0, nelts = config->secure_ports->nelts; i < nelts; ++i) { >+ port_ptr = APR_ARRAY_IDX(config->secure_ports, i, unsigned short); >+ if (port_ptr == parsed_port) { >+ secure = "on"; >+ break; >+ } >+ } >+ } >+ } >+ else if (secure && !inport && config->secure_ports && config->secure_ports->nelts) { >+ /* User has set RemoteIPServerPortHeader and port is set, but not received, >+ RemoteIPSSLPorts is also set. Revert to first port in list. */ >+ parsed_port = APR_ARRAY_IDX(config->secure_ports, 0, unsigned short); >+ } >+ > /* Port is not known so set it to zero; otherwise it can be misleading */ > req->useragent_addr->port = 0; > >@@ -719,18 +893,91 @@ static int remoteip_modify_request(request_rec *r) > } > } > >+ if (parsed_port) { >+ /* By all paths, parsed_port cannot be 0 if secure is not NULL */ >+ if (secure) { >+ apr_table_setn(r->subprocess_env, "HTTPS", "on"); >+ proxy_note = apr_psprintf(r->pool, >+ "s:%u", >+ parsed_port); >+ } >+ else { >+ proxy_note = apr_psprintf(r->pool, >+ "i:%u", >+ parsed_port); >+ } >+ } >+ else { >+ proxy_note = "i"; >+ } >+ apr_table_setn(r->notes, "remoteip-data", proxy_note); >+ > r->useragent_addr = req->useragent_addr; > r->useragent_ip = req->useragent_ip; > > ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, > req->proxy_ips >- ? "Using %s as client's IP by proxies %s" >- : "Using %s as client's IP by internal proxies%s", >+ ? "Using %s as client's IP by %s proxies %s via" >+ : "Using %s as client's IP by %s internal proxies %s", > req->useragent_ip, >+ secure ? "HTTPS" : "HTTP", > (req->proxy_ips ? req->proxy_ips : "")); > return OK; > } > >+static int remoteip_ssl_hook_Fixup(request_rec *r) >+{ >+ request_rec *current = r; >+ /* for internal redirect via mod_rewrite and other handlers */ >+ >+ char* remdata; >+ while (current) { >+ remdata = (char *) apr_table_get(current->notes, "remoteip-data"); >+ /* if present, only values it can start with are http or https */ >+ if (remdata) { >+ if (remdata[0] == 's') >+ apr_table_setn(r->subprocess_env, "HTTPS", "on"); >+ break; >+ } >+ current = current->prev; >+ } >+ return OK; >+} >+ >+static const char* remoteip_read_scheme(const request_rec *r) >+{ >+ request_rec *current = (request_rec *) r; >+ char* remdata; >+ while (current) { >+ remdata = (char *) apr_table_get(current->notes, "remoteip-data"); >+ if (remdata) { >+ if (remdata[0] == 's') >+ return "https"; >+ break; >+ } >+ current = current->prev; >+ } >+ return NULL; >+} >+ >+static unsigned short remoteip_read_port(const request_rec *r) >+{ >+ request_rec *current = (request_rec *) r; >+ char* remdata; >+ while (current) { >+ remdata = (char *) apr_table_get(current->notes, "remoteip-data"); >+ if (remdata) { >+ if (remdata[1] == ':') { >+ return atoi(remdata + 2); >+ } >+ break; >+ } >+ current = current->prev; >+ } >+ /* fall-back to other means of determining port */ >+ return 0; >+} >+ > static int remoteip_is_server_port(apr_port_t port) > { > ap_listen_rec *lr; >@@ -827,7 +1074,7 @@ static remoteip_parse_status_t remoteip_process_v1_header(conn_rec *c, > > /* parse client-port */ > GET_NEXT_WORD("client-port") >- if (sscanf(word, "%hu", &port) != 1) { >+ if (parse_validate_port(word, &port)) { > ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03501) > "RemoteIPProxyProtocol: error parsing port '%s' in header '%s'", > word, hdr->v1.line); >@@ -835,7 +1082,16 @@ static remoteip_parse_status_t remoteip_process_v1_header(conn_rec *c, > } > > /* parse dest-port */ >- /* GET_NEXT_WORD("destination-port") - no-op since we don't care about it */ >+ GET_NEXT_WORD("destination-port") >+ >+ if (parse_validate_port(word, &conn_conf->server_port)) { >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, c, APLOGNO(03515) >+ "RemoteIPProxyProtocol: error parsing port '%s' in header '%s'", >+ word, hdr->v1.line); >+ return HDR_ERROR; >+ } >+ >+#undef GET_NEXT_WORD > > /* create a socketaddr from the info */ > ret = apr_sockaddr_info_get(&conn_conf->client_addr, host, family, port, 0, >@@ -935,6 +1191,7 @@ static remoteip_parse_status_t remoteip_process_v2_header(conn_rec *c, > return HDR_ERROR; > } > >+ conn_conf->server_port = ntohs(hdr->v2.addr.ip4.dst_port); > conn_conf->client_addr->sa.sin.sin_addr.s_addr = > hdr->v2.addr.ip4.src_addr; > break; >@@ -951,6 +1208,7 @@ static remoteip_parse_status_t remoteip_process_v2_header(conn_rec *c, > "RemoteIPProxyProtocol: error creating sockaddr"); > return HDR_ERROR; > } >+ conn_conf->server_port = ntohs(hdr->v2.addr.ip6.dst_port); > memcpy(&conn_conf->client_addr->sa.sin6.sin6_addr.s6_addr, > hdr->v2.addr.ip6.src_addr, 16); > break; >@@ -1232,6 +1490,17 @@ static const command_rec remoteip_cmds[] = > RSRC_CONF | EXEC_ON_READ, > "The filename to read the list of internal proxies, " > "see the RemoteIPInternalProxy directive"), >+ AP_INIT_TAKE2("RemoteIPSecureHeader", secure_header_set, NULL, RSRC_CONF, >+ "Specifies a request header and value that indicates a secure connection, " >+ "e.g. \"X-Forwarded-Proto https\" or \"X-Secure-Connection on\""), >+ AP_INIT_TAKE1("RemoteIPServerPortHeader", server_port_header_name_set, NULL, >+ RSRC_CONF, >+ "Header by which remote server tells which port the connection came in on."), >+ AP_INIT_TAKE_ARGV("RemoteIPSSLPorts", secure_ports_set, NULL, RSRC_CONF, >+ "Port to be used for redirections if RemoteIPSecureHeader is set, " >+ "Default is \"RemoteIPSSLPorts 443\".\n" >+ "Example \"RemoteIPSSLPorts 443 8443\"\n" >+ "If RemoteIPServerPortHeader is unused, defaults to first port in list."), > AP_INIT_TAKE1("RemoteIPProxyProtocol", remoteip_enable_proxy_protocol, NULL, > RSRC_CONF, "Enable PROXY protocol handling (`on', `off', `optional')"), > { NULL } >@@ -1248,7 +1517,10 @@ static void register_hooks(apr_pool_t *p) > ap_hook_pre_config(remoteip_hook_pre_config, NULL, NULL, APR_HOOK_MIDDLE); > 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_post_headers_parsed(remoteip_modify_request, NULL, NULL, APR_HOOK_FIRST); >+ ap_hook_http_scheme(remoteip_read_scheme, NULL, NULL, APR_HOOK_FIRST); >+ ap_hook_default_port(remoteip_read_port, NULL, NULL, APR_HOOK_FIRST); >+ ap_hook_fixups(remoteip_ssl_hook_Fixup, NULL, NULL, APR_HOOK_MIDDLE); > } > > AP_DECLARE_MODULE(remoteip) = { >diff --git a/server/protocol.c b/server/protocol.c >index 8cf5a7d..678a2d1 100644 >--- a/server/protocol.c >+++ b/server/protocol.c >@@ -70,6 +70,7 @@ APR_HOOK_STRUCT( > APR_HOOK_LINK(protocol_propose) > APR_HOOK_LINK(protocol_switch) > APR_HOOK_LINK(protocol_get) >+ APR_HOOK_LINK(post_headers_parsed) > ) > > AP_DECLARE_DATA ap_filter_rec_t *ap_old_write_func = NULL; >@@ -1359,6 +1360,16 @@ request_rec *ap_read_request(conn_rec *conn) > > apr_brigade_destroy(tmp_bb); > >+ if (access_status = ap_run_post_headers_parsed(r)) { >+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, >+ "post_headers_parsed hooks returned failure"); >+ ap_die(access_status, r); >+ ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); >+ ap_run_log_transaction(r); >+ r = NULL; >+ goto traceout; >+ } >+ > /* update what we think the virtual host is based on the headers we've > * now read. may update status. > */ >@@ -2382,3 +2393,5 @@ AP_IMPLEMENT_HOOK_RUN_FIRST(int,protocol_switch, > (c, r, s, protocol), DECLINED) > AP_IMPLEMENT_HOOK_RUN_FIRST(const char *,protocol_get, > (const conn_rec *c), (c), NULL) >+AP_IMPLEMENT_HOOK_RUN_ALL(int, post_headers_parsed, >+ (request_rec *r), (r), OK, DECLINED) >diff --git a/server/vhost.c b/server/vhost.c >index 5ad4efd..8bf3ec3 100644 >--- a/server/vhost.c >+++ b/server/vhost.c >@@ -998,7 +998,9 @@ static void check_hostalias(request_rec *r) > virthost_s = NULL; > last_s = NULL; > >- port = r->connection->local_addr->port; >+ port = ap_default_port(r); >+ if (port == 0) >+ port = r->connection->local_addr->port; > > /* Recall that the name_chain is a list of server_addr_recs, some of > * whose ports may not match. Also each server may appear more than >@@ -1065,7 +1067,9 @@ static void check_serverpath(request_rec *r) > name_chain *src; > apr_port_t port; > >- port = r->connection->local_addr->port; >+ port = ap_default_port(r); >+ if (port == 0) >+ port = r->connection->local_addr->port; > > /* > * This is in conjunction with the ServerPath code in http_core, so we
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 59829
:
34024
|
34249
|
34495
|
34496
|
34504
|
34506
|
34507
|
34518
|
34709
|
34711
|
34741
|
34774
| 34781