Loading docs/manual/mod/mod_remoteip.xml +30 −23 Original line number Diff line number Diff line Loading @@ -223,19 +223,19 @@ RemoteIPProxiesHeader X-Forwarded-By <directivesynopsis> <name>RemoteIPProxyProtocol</name> <description>Enable, optionally enable or disable the PROXY protocol handling</description> <syntax>RemoteIPProxyProtocol On|Optional|Off</syntax> <description>Enable or disable PROXY protocol handling</description> <syntax>RemoteIPProxyProtocol On|Off</syntax> <contextlist><context>server config</context><context>virtual host</context> </contextlist> <compatibility>RemoteIPProxyProtocol is only available in httpd 2.4.26 and newer</compatibility> <usage> <p>The <directive>RemoteIPProxyProtocol</directive> enables or <p>The <directive>RemoteIPProxyProtocol</directive> directive enables or disables the reading and handling of the PROXY protocol connection header. If enabled with the <code>On</code> flag, the upstream client <em>must</em> send the header every time it opens a connection or the connection will be aborted. If enabled with the <code>Optional</code> flag, the upstream client <em>may</em> send the header.</p> be aborted unless it is in the list of disabled hosts provided by <directive module="mod_remoteip">RemoteIPProxyProtocolDisableHosts</directive> directive. <p>While this directive may be specified in any virtual host, it is important to understand that because the PROXY protocol is connection Loading @@ -247,45 +247,52 @@ RemoteIPProxiesHeader X-Forwarded-By in the other, that won't work; in such a case the last one wins and a notice will be logged indicating which setting was being overridden.</p> <note type="hint">When multiple virtual hosts on the same IP and port are configured with a combination of <code>On</code> and <code>Optional</code> flags, connections will not be aborted if the header is not sent. Instead, enforcement will happen after the request is read so virtual hosts configured with <code>On</code> will return a 400 Bad Request. Virtual hosts configured with <code>Optional</code> will continue as usual but without replacing the client IP information</note> <highlight language="config"> Listen 80 <VirtualHost *:80> ServerName www.example.com RemoteIPProxyProtocol Optional #Requests to this virtual host may optionally not have # a PROXY protocol header provided </VirtualHost> <VirtualHost *:80> ServerName www.example.com RemoteIPProxyProtocol On #Requests to this virtual host must have a PROXY protocol # header provided. If it is missing, a 400 will result # header provided. If it is missing, the connection will # be aborted </VirtualHost> Listen 8080 <VirtualHost *:8080> ServerName www.example.com RemoteIPProxyProtocol On RemoteIPProxyProtocolDisableHosts 127.0.0.1 10.0.0.0/8 #Requests to this virtual host must have a PROXY protocol # header provided. If it is missing, the connection will # be aborted # be aborted except when coming from localhost or the # 10.x.x.x RFC1918 range </VirtualHost> </highlight> </usage> </directivesynopsis> <directivesynopsis> <name>RemoteIPProxyProtocolDisableHosts</name> <description>Disable processing of PROXY header for certain hosts or networks</description> <syntax>RemoteIPProxyProtocolDisableHosts host|range [host|range] [host|range]</syntax> <contextlist><context>server config</context><context>virtual host</context> </contextlist> <compatibility>RemoteIPProxyProtocolDisableHosts is only available in httpd 2.4.26 and newer</compatibility> <usage> <p>The <directive>RemoteIPProxyProtocol</directive> directive enables or disables the reading and handling of the PROXY protocol connection header. Sometimes it is desirable to require clients to provide the PROXY header, but permit other clients to connect without it. This directive allows a server administrator to configure a single host or CIDR range of hosts that may do so. This is generally useful for useful for monitoring and administrative traffic to a virtual host direct to the server behind the upstream load balancer.</p> </usage> </directivesynopsis> <directivesynopsis> <name>RemoteIPTrustedProxy</name> <description>Restrict client IP addresses trusted to present the RemoteIPHeader value</description> Loading modules/metadata/mod_remoteip.c +98 −174 Original line number Diff line number Diff line Loading @@ -61,14 +61,9 @@ typedef struct { apr_array_header_t *proxymatch_ip; remoteip_addr_info *proxy_protocol_enabled; remoteip_addr_info *proxy_protocol_optional; remoteip_addr_info *proxy_protocol_disabled; /** A flag indicating whether or not proxyprotocol * is optoinal for this specific server */ int pp_optional; apr_array_header_t *disabled_subnets; apr_pool_t *pool; } remoteip_config_t; Loading Loading @@ -150,22 +145,18 @@ typedef struct { apr_sockaddr_t *client_addr; /** Character representation of the client */ char *client_ip; /** Flag indicating that the PROXY header may be omitted on this connection (do not abort if it is missing). */ int proxy_protocol_optional; } remoteip_conn_config_t; typedef enum { HDR_DONE, HDR_ERROR, HDR_MISSING, HDR_NEED_MORE } remoteip_parse_status_t; typedef enum { HDR_DONE, HDR_ERROR, HDR_NEED_MORE } remoteip_parse_status_t; static void *create_remoteip_server_config(apr_pool_t *p, server_rec *s) { remoteip_config_t *config = apr_pcalloc(p, sizeof *config); remoteip_config_t *config = apr_pcalloc(p, sizeof(*config)); config->disabled_subnets = apr_array_make(p, 1, sizeof(apr_ipsubnet_t *)); /* config->header_name = NULL; * config->proxies_header_name = NULL; * config->proxy_protocol_enabled = NULL; * config->proxy_protocol_optional = NULL; * config->proxy_protocol_disabled = NULL; * config->pp_optional = 0; */ config->pool = p; return config; Loading @@ -188,9 +179,6 @@ 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->pp_optional = server->pp_optional ? server->pp_optional : global->pp_optional; return config; } Loading Loading @@ -363,7 +351,7 @@ static int remoteip_addr_in_list(remoteip_addr_info *list, apr_sockaddr_t *addr) return 0; } static void remoteip_warn_enable_conflict(remoteip_addr_info *prev, server_rec *new, const char* arg) static void remoteip_warn_enable_conflict(remoteip_addr_info *prev, server_rec *new, int flag) { char buf[INET6_ADDRSTRLEN]; Loading @@ -376,70 +364,51 @@ static void remoteip_warn_enable_conflict(remoteip_addr_info *prev, server_rec * buf, prev->addr->port, prev->source->server_hostname, prev->source->addrs->host_port, prev->source->defn_name, new->server_hostname, new->addrs->host_port, new->defn_name, arg); flag ? "On" : "Off"); } static const char *remoteip_enable_proxy_protocol(cmd_parms *cmd, void *config, const char *arg) int flag) { remoteip_config_t *global_conf; remoteip_config_t *server_conf; remoteip_config_t *conf; server_addr_rec *addr; remoteip_addr_info **add; int list_len = 2; remoteip_addr_info **rem_list[list_len]; remoteip_addr_info **rem; remoteip_addr_info *list; int i; global_conf = ap_get_module_config(ap_server_conf->module_config, &remoteip_module); server_conf = ap_get_module_config(cmd->server->module_config, conf = ap_get_module_config(ap_server_conf->module_config, &remoteip_module); if (strcasecmp(arg, "On") == 0) { add = &global_conf->proxy_protocol_enabled; rem_list[0] = &global_conf->proxy_protocol_optional; rem_list[1] = &global_conf->proxy_protocol_disabled; } else if (strcasecmp(arg, "Optional") == 0) { add = &global_conf->proxy_protocol_optional; rem_list[0] = &global_conf->proxy_protocol_enabled; rem_list[1] = &global_conf->proxy_protocol_disabled; server_conf->pp_optional = 1; } else if (strcasecmp(arg, "Off") == 0 ) { add = &global_conf->proxy_protocol_disabled; rem_list[0] = &global_conf->proxy_protocol_enabled; rem_list[1] = &global_conf->proxy_protocol_optional; if (flag) { add = &conf->proxy_protocol_enabled; rem = &conf->proxy_protocol_disabled; } else { return apr_pstrcat(cmd->pool, "Unrecognized option for %s `%s'", cmd->cmd->name, arg, NULL); add = &conf->proxy_protocol_disabled; rem = &conf->proxy_protocol_enabled; } for (addr = cmd->server->addrs; addr; addr = addr->next) { /* remove address from other lists */ for (i = 0; i < list_len ; i++) { remoteip_addr_info **rem = rem_list[i]; /* remove address from opposite list */ if (*rem) { if (remoteip_sockaddr_equal((*rem)->addr, addr->host_addr)) { remoteip_warn_enable_conflict(*rem, cmd->server, arg); remoteip_warn_enable_conflict(*rem, cmd->server, flag); *rem = (*rem)->next; } else { for (list = *rem; list->next; list = list->next) { if (remoteip_sockaddr_equal(list->next->addr, addr->host_addr)) { remoteip_warn_enable_conflict(list->next, cmd->server, arg); remoteip_warn_enable_conflict(list->next, cmd->server, flag); list->next = list->next->next; break; } } } } } /* add address to desired list */ if (!remoteip_addr_in_list(*add, addr->host_addr)) { remoteip_addr_info *info = apr_palloc(global_conf->pool, sizeof(*info)); remoteip_addr_info *info = apr_palloc(conf->pool, sizeof(*info)); info->addr = addr->host_addr; info->source = cmd->server; info->next = *add; Loading @@ -450,6 +419,45 @@ static const char *remoteip_enable_proxy_protocol(cmd_parms *cmd, void *config, return NULL; } static const char *remoteip_disable_networks(cmd_parms *cmd, void *d, int argc, char *const argv[]) { int i; apr_pool_t *ptemp = cmd->temp_pool; apr_pool_t *p = cmd->pool; remoteip_config_t *conf = ap_get_module_config(ap_server_conf->module_config, &remoteip_module); if (argc == 0) return "RemoteIPProxyProtocolDisableNetworks requires an argument"; for (i=0; i<argc; i++) { char *addr = apr_pstrdup(ptemp, argv[i]); char *mask; apr_status_t rv; apr_ipsubnet_t **ip = apr_pcalloc(p, sizeof(apr_ipsubnet_t *)); if ((mask = ap_strchr(addr, '/'))) *mask++ = '\0'; rv = apr_ipsubnet_create(ip, addr, mask, p); if(APR_STATUS_IS_EINVAL(rv)) { /* looked nothing like an IP address */ return apr_psprintf(p, "ip address '%s' appears to be invalid", addr); } else if (rv != APR_SUCCESS) { return apr_psprintf(p, "ip address '%s' appears to be invalid: %pm", addr, &rv); } *(apr_ipsubnet_t**)apr_array_push(conf->disabled_subnets) = *ip; } return NULL; } static int remoteip_hook_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) { Loading @@ -476,11 +484,6 @@ static int remoteip_hook_post_config(apr_pool_t *pconf, apr_pool_t *plog, ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(03492) "RemoteIPProxyProtocol: enabled on %s:%hu", buf, info->addr->port); } for (info = conf->proxy_protocol_optional; info; info = info->next) { apr_sockaddr_ip_getbuf(buf, sizeof(buf), info->addr); ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(03493) "RemoteIPProxyProtocol: optional on %s:%hu", buf, info->addr->port); } for (info = conf->proxy_protocol_disabled; info; info = info->next) { apr_sockaddr_ip_getbuf(buf, sizeof(buf), info->addr); ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(03494) Loading Loading @@ -523,19 +526,11 @@ static int remoteip_modify_request(request_rec *r) protocol handling allowing it to take precedence and return */ if (conn_config) { /* We may have gotten here if processing was optional - check for that */ if (!conn_config->client_addr) { 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; } else { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(03496) "RemoteIPProxyProtocol data is missing, but required! Aborting request."); return HTTP_BAD_REQUEST; } } r->useragent_addr = conn_config->client_addr; r->useragent_ip = conn_config->client_ip; Loading Loading @@ -860,7 +855,7 @@ static int remoteip_hook_pre_connection(conn_rec *c, void *csd) { remoteip_config_t *conf; remoteip_conn_config_t *conn_conf; int optional; int i; /* Do not attempt to manipulate slave connections */ if (c->master != NULL) { Loading @@ -870,13 +865,19 @@ static int remoteip_hook_pre_connection(conn_rec *c, void *csd) conf = ap_get_module_config(ap_server_conf->module_config, &remoteip_module); /* Used twice - do the check only once */ optional = remoteip_addr_in_list(conf->proxy_protocol_optional, c->local_addr); /* check if we're enabled for this connection */ if ((!remoteip_addr_in_list(conf->proxy_protocol_enabled, c->local_addr) && !optional ) 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; } /* We are enabled for this IP/port, but check that we aren't explicitly disabled */ for (i = 0; i < conf->disabled_subnets->nelts; i++) { apr_ipsubnet_t *ip = ((apr_ipsubnet_t**)conf->disabled_subnets->elts)[i]; if (ip && apr_ipsubnet_test(ip, c->client_addr)) return DECLINED; } Loading @@ -898,12 +899,6 @@ static int remoteip_hook_pre_connection(conn_rec *c, void *csd) /* this holds the resolved proxy info for this connection */ conn_conf = apr_pcalloc(c->pool, sizeof(*conn_conf)); /* Propagate the optional flag so the connection handler knows not to abort if the header is mising. NOTE: This means we must check after we read the request that the header was NOT optional, too. */ conn_conf->proxy_protocol_optional = optional; ap_set_module_config(c->conn_config, &remoteip_module, conn_conf); return OK; Loading Loading @@ -1036,31 +1031,20 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, remoteip_parse_status_t psts = HDR_NEED_MORE; const char *ptr; apr_size_t len; apr_size_t this_read = 0; /* Track bytes read in each brigade */ apr_size_t prev_read = 0; if (f->c->aborted) { return APR_ECONNABORTED; } conn_conf = ap_get_module_config(f->c->conn_config, &remoteip_module); /* allocate/retrieve the context that holds our header */ if (!ctx) { ctx = f->ctx = apr_palloc(f->c->pool, sizeof(*ctx)); ctx->rcvd = 0; ctx->need = MIN_HDR_LEN; ctx->version = 0; ctx->mode = AP_MODE_READBYTES; ctx->bb = apr_brigade_create(f->c->pool, f->c->bucket_alloc); ctx->done = 0; if (conn_conf->proxy_protocol_optional) { ctx->mode = AP_MODE_SPECULATIVE; ctx->peeking = 1; } else { ctx->mode = AP_MODE_READBYTES; ctx->peeking = 0; } } if (ctx->done) { Loading @@ -1071,6 +1055,8 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, return ap_get_brigade(f->next, bb_out, mode, block, readbytes); } conn_conf = ap_get_module_config(f->c->conn_config, &remoteip_module); /* try to read a header's worth of data */ while (!ctx->done) { if (APR_BRIGADE_EMPTY(ctx->bb)) { Loading @@ -1084,23 +1070,9 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, return block == APR_NONBLOCK_READ ? APR_SUCCESS : APR_EOF; } if (ctx->peeking) { ctx->rcvd = 0; ctx->need = MIN_HDR_LEN; } while (!ctx->done && !APR_BRIGADE_EMPTY(ctx->bb)) { b = APR_BRIGADE_FIRST(ctx->bb); if (ctx->peeking && APR_BUCKET_IS_EOS(b)) { /* Shortcut - we know no header was found yet and an EOS indicates we never will */ apr_brigade_destroy(ctx->bb); ctx->bb = NULL; ctx->done = 1; return APR_SUCCESS; } ret = apr_bucket_read(b, &ptr, &len, block); if (APR_STATUS_IS_EAGAIN(ret) && block == APR_NONBLOCK_READ) { return APR_SUCCESS; Loading @@ -1112,10 +1084,6 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, memcpy(ctx->header + ctx->rcvd, ptr, len); ctx->rcvd += len; if (ctx->peeking && block == APR_NONBLOCK_READ) { this_read += len; } apr_bucket_delete(b); psts = HDR_NEED_MORE; Loading @@ -1123,37 +1091,8 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, /* reading initial chunk */ if (ctx->rcvd >= MIN_HDR_LEN) { ctx->version = remoteip_determine_version(f->c, ctx->header); /* We've read enough to know that a header is present. In peek mode we purge the bb and can decide to step aside or switch to non-speculative read to consume the data */ if (ctx->peeking) { if (ctx->version < 0) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, APLOGNO(03512) "RemoteIPProxyProtocol: PROXY header is missing from " "request. Stepping aside."); apr_brigade_destroy(ctx->bb); ctx->bb = NULL; ctx->done = 1; return ap_get_brigade(f->next, bb_out, mode, block, readbytes); } else { /* Rest ctx to initial values */ ctx->rcvd = 0; ctx->need = MIN_HDR_LEN; ctx->version = 0; ctx->done = 0; ctx->mode = AP_MODE_READBYTES; ctx->peeking = 0; apr_brigade_cleanup(ctx->bb); ap_get_brigade(f->next, ctx->bb, ctx->mode, block, ctx->need - ctx->rcvd); } } else { if (ctx->version < 0) { psts = HDR_MISSING; psts = HDR_ERROR; } else if (ctx->version == 1) { ctx->mode = AP_MODE_GETLINE; Loading @@ -1164,7 +1103,6 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, } } } } else if (ctx->version == 1) { psts = remoteip_process_v1_header(f->c, conn_conf, (proxy_header *) ctx->header, Loading @@ -1174,7 +1112,6 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, if (ctx->rcvd >= MIN_V2_HDR_LEN) { ctx->need = MIN_V2_HDR_LEN + remoteip_get_v2_len((proxy_header *) ctx->header); } if (ctx->rcvd >= ctx->need) { psts = remoteip_process_v2_header(f->c, conn_conf, Loading @@ -1191,10 +1128,6 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, } switch (psts) { case HDR_MISSING: ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(03510) "RemoteIPProxyProtocol: no valid PROXY header found"); /* fall through to error case */ case HDR_ERROR: f->c->aborted = 1; apr_brigade_destroy(ctx->bb); Loading @@ -1208,18 +1141,6 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, break; } } /* In SPECULATIVE mode, upstream will return all data on each brigade get - even data we've seen. For non blocking read, make sure we got new data or return early when we haven't */ if (ctx->peeking && block == APR_NONBLOCK_READ) { if (this_read == prev_read) { return APR_SUCCESS; } else { prev_read = this_read; } } } /* we only get here when done == 1 */ Loading Loading @@ -1268,8 +1189,11 @@ 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_TAKE1("RemoteIPProxyProtocol", remoteip_enable_proxy_protocol, NULL, RSRC_CONF, "Enable PROXY protocol handling (`on', `off', `optional')"), AP_INIT_FLAG("RemoteIPProxyProtocol", remoteip_enable_proxy_protocol, NULL, RSRC_CONF, "Enable PROXY protocol handling (`on', `off')"), AP_INIT_TAKE_ARGV("RemoteIPProxyProtocolDisableHosts", remoteip_disable_networks, NULL, RSRC_CONF, "Disable PROXY " "protocol handling for this list of networks in CIDR format"), { NULL } }; Loading Loading
docs/manual/mod/mod_remoteip.xml +30 −23 Original line number Diff line number Diff line Loading @@ -223,19 +223,19 @@ RemoteIPProxiesHeader X-Forwarded-By <directivesynopsis> <name>RemoteIPProxyProtocol</name> <description>Enable, optionally enable or disable the PROXY protocol handling</description> <syntax>RemoteIPProxyProtocol On|Optional|Off</syntax> <description>Enable or disable PROXY protocol handling</description> <syntax>RemoteIPProxyProtocol On|Off</syntax> <contextlist><context>server config</context><context>virtual host</context> </contextlist> <compatibility>RemoteIPProxyProtocol is only available in httpd 2.4.26 and newer</compatibility> <usage> <p>The <directive>RemoteIPProxyProtocol</directive> enables or <p>The <directive>RemoteIPProxyProtocol</directive> directive enables or disables the reading and handling of the PROXY protocol connection header. If enabled with the <code>On</code> flag, the upstream client <em>must</em> send the header every time it opens a connection or the connection will be aborted. If enabled with the <code>Optional</code> flag, the upstream client <em>may</em> send the header.</p> be aborted unless it is in the list of disabled hosts provided by <directive module="mod_remoteip">RemoteIPProxyProtocolDisableHosts</directive> directive. <p>While this directive may be specified in any virtual host, it is important to understand that because the PROXY protocol is connection Loading @@ -247,45 +247,52 @@ RemoteIPProxiesHeader X-Forwarded-By in the other, that won't work; in such a case the last one wins and a notice will be logged indicating which setting was being overridden.</p> <note type="hint">When multiple virtual hosts on the same IP and port are configured with a combination of <code>On</code> and <code>Optional</code> flags, connections will not be aborted if the header is not sent. Instead, enforcement will happen after the request is read so virtual hosts configured with <code>On</code> will return a 400 Bad Request. Virtual hosts configured with <code>Optional</code> will continue as usual but without replacing the client IP information</note> <highlight language="config"> Listen 80 <VirtualHost *:80> ServerName www.example.com RemoteIPProxyProtocol Optional #Requests to this virtual host may optionally not have # a PROXY protocol header provided </VirtualHost> <VirtualHost *:80> ServerName www.example.com RemoteIPProxyProtocol On #Requests to this virtual host must have a PROXY protocol # header provided. If it is missing, a 400 will result # header provided. If it is missing, the connection will # be aborted </VirtualHost> Listen 8080 <VirtualHost *:8080> ServerName www.example.com RemoteIPProxyProtocol On RemoteIPProxyProtocolDisableHosts 127.0.0.1 10.0.0.0/8 #Requests to this virtual host must have a PROXY protocol # header provided. If it is missing, the connection will # be aborted # be aborted except when coming from localhost or the # 10.x.x.x RFC1918 range </VirtualHost> </highlight> </usage> </directivesynopsis> <directivesynopsis> <name>RemoteIPProxyProtocolDisableHosts</name> <description>Disable processing of PROXY header for certain hosts or networks</description> <syntax>RemoteIPProxyProtocolDisableHosts host|range [host|range] [host|range]</syntax> <contextlist><context>server config</context><context>virtual host</context> </contextlist> <compatibility>RemoteIPProxyProtocolDisableHosts is only available in httpd 2.4.26 and newer</compatibility> <usage> <p>The <directive>RemoteIPProxyProtocol</directive> directive enables or disables the reading and handling of the PROXY protocol connection header. Sometimes it is desirable to require clients to provide the PROXY header, but permit other clients to connect without it. This directive allows a server administrator to configure a single host or CIDR range of hosts that may do so. This is generally useful for useful for monitoring and administrative traffic to a virtual host direct to the server behind the upstream load balancer.</p> </usage> </directivesynopsis> <directivesynopsis> <name>RemoteIPTrustedProxy</name> <description>Restrict client IP addresses trusted to present the RemoteIPHeader value</description> Loading
modules/metadata/mod_remoteip.c +98 −174 Original line number Diff line number Diff line Loading @@ -61,14 +61,9 @@ typedef struct { apr_array_header_t *proxymatch_ip; remoteip_addr_info *proxy_protocol_enabled; remoteip_addr_info *proxy_protocol_optional; remoteip_addr_info *proxy_protocol_disabled; /** A flag indicating whether or not proxyprotocol * is optoinal for this specific server */ int pp_optional; apr_array_header_t *disabled_subnets; apr_pool_t *pool; } remoteip_config_t; Loading Loading @@ -150,22 +145,18 @@ typedef struct { apr_sockaddr_t *client_addr; /** Character representation of the client */ char *client_ip; /** Flag indicating that the PROXY header may be omitted on this connection (do not abort if it is missing). */ int proxy_protocol_optional; } remoteip_conn_config_t; typedef enum { HDR_DONE, HDR_ERROR, HDR_MISSING, HDR_NEED_MORE } remoteip_parse_status_t; typedef enum { HDR_DONE, HDR_ERROR, HDR_NEED_MORE } remoteip_parse_status_t; static void *create_remoteip_server_config(apr_pool_t *p, server_rec *s) { remoteip_config_t *config = apr_pcalloc(p, sizeof *config); remoteip_config_t *config = apr_pcalloc(p, sizeof(*config)); config->disabled_subnets = apr_array_make(p, 1, sizeof(apr_ipsubnet_t *)); /* config->header_name = NULL; * config->proxies_header_name = NULL; * config->proxy_protocol_enabled = NULL; * config->proxy_protocol_optional = NULL; * config->proxy_protocol_disabled = NULL; * config->pp_optional = 0; */ config->pool = p; return config; Loading @@ -188,9 +179,6 @@ 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->pp_optional = server->pp_optional ? server->pp_optional : global->pp_optional; return config; } Loading Loading @@ -363,7 +351,7 @@ static int remoteip_addr_in_list(remoteip_addr_info *list, apr_sockaddr_t *addr) return 0; } static void remoteip_warn_enable_conflict(remoteip_addr_info *prev, server_rec *new, const char* arg) static void remoteip_warn_enable_conflict(remoteip_addr_info *prev, server_rec *new, int flag) { char buf[INET6_ADDRSTRLEN]; Loading @@ -376,70 +364,51 @@ static void remoteip_warn_enable_conflict(remoteip_addr_info *prev, server_rec * buf, prev->addr->port, prev->source->server_hostname, prev->source->addrs->host_port, prev->source->defn_name, new->server_hostname, new->addrs->host_port, new->defn_name, arg); flag ? "On" : "Off"); } static const char *remoteip_enable_proxy_protocol(cmd_parms *cmd, void *config, const char *arg) int flag) { remoteip_config_t *global_conf; remoteip_config_t *server_conf; remoteip_config_t *conf; server_addr_rec *addr; remoteip_addr_info **add; int list_len = 2; remoteip_addr_info **rem_list[list_len]; remoteip_addr_info **rem; remoteip_addr_info *list; int i; global_conf = ap_get_module_config(ap_server_conf->module_config, &remoteip_module); server_conf = ap_get_module_config(cmd->server->module_config, conf = ap_get_module_config(ap_server_conf->module_config, &remoteip_module); if (strcasecmp(arg, "On") == 0) { add = &global_conf->proxy_protocol_enabled; rem_list[0] = &global_conf->proxy_protocol_optional; rem_list[1] = &global_conf->proxy_protocol_disabled; } else if (strcasecmp(arg, "Optional") == 0) { add = &global_conf->proxy_protocol_optional; rem_list[0] = &global_conf->proxy_protocol_enabled; rem_list[1] = &global_conf->proxy_protocol_disabled; server_conf->pp_optional = 1; } else if (strcasecmp(arg, "Off") == 0 ) { add = &global_conf->proxy_protocol_disabled; rem_list[0] = &global_conf->proxy_protocol_enabled; rem_list[1] = &global_conf->proxy_protocol_optional; if (flag) { add = &conf->proxy_protocol_enabled; rem = &conf->proxy_protocol_disabled; } else { return apr_pstrcat(cmd->pool, "Unrecognized option for %s `%s'", cmd->cmd->name, arg, NULL); add = &conf->proxy_protocol_disabled; rem = &conf->proxy_protocol_enabled; } for (addr = cmd->server->addrs; addr; addr = addr->next) { /* remove address from other lists */ for (i = 0; i < list_len ; i++) { remoteip_addr_info **rem = rem_list[i]; /* remove address from opposite list */ if (*rem) { if (remoteip_sockaddr_equal((*rem)->addr, addr->host_addr)) { remoteip_warn_enable_conflict(*rem, cmd->server, arg); remoteip_warn_enable_conflict(*rem, cmd->server, flag); *rem = (*rem)->next; } else { for (list = *rem; list->next; list = list->next) { if (remoteip_sockaddr_equal(list->next->addr, addr->host_addr)) { remoteip_warn_enable_conflict(list->next, cmd->server, arg); remoteip_warn_enable_conflict(list->next, cmd->server, flag); list->next = list->next->next; break; } } } } } /* add address to desired list */ if (!remoteip_addr_in_list(*add, addr->host_addr)) { remoteip_addr_info *info = apr_palloc(global_conf->pool, sizeof(*info)); remoteip_addr_info *info = apr_palloc(conf->pool, sizeof(*info)); info->addr = addr->host_addr; info->source = cmd->server; info->next = *add; Loading @@ -450,6 +419,45 @@ static const char *remoteip_enable_proxy_protocol(cmd_parms *cmd, void *config, return NULL; } static const char *remoteip_disable_networks(cmd_parms *cmd, void *d, int argc, char *const argv[]) { int i; apr_pool_t *ptemp = cmd->temp_pool; apr_pool_t *p = cmd->pool; remoteip_config_t *conf = ap_get_module_config(ap_server_conf->module_config, &remoteip_module); if (argc == 0) return "RemoteIPProxyProtocolDisableNetworks requires an argument"; for (i=0; i<argc; i++) { char *addr = apr_pstrdup(ptemp, argv[i]); char *mask; apr_status_t rv; apr_ipsubnet_t **ip = apr_pcalloc(p, sizeof(apr_ipsubnet_t *)); if ((mask = ap_strchr(addr, '/'))) *mask++ = '\0'; rv = apr_ipsubnet_create(ip, addr, mask, p); if(APR_STATUS_IS_EINVAL(rv)) { /* looked nothing like an IP address */ return apr_psprintf(p, "ip address '%s' appears to be invalid", addr); } else if (rv != APR_SUCCESS) { return apr_psprintf(p, "ip address '%s' appears to be invalid: %pm", addr, &rv); } *(apr_ipsubnet_t**)apr_array_push(conf->disabled_subnets) = *ip; } return NULL; } static int remoteip_hook_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) { Loading @@ -476,11 +484,6 @@ static int remoteip_hook_post_config(apr_pool_t *pconf, apr_pool_t *plog, ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(03492) "RemoteIPProxyProtocol: enabled on %s:%hu", buf, info->addr->port); } for (info = conf->proxy_protocol_optional; info; info = info->next) { apr_sockaddr_ip_getbuf(buf, sizeof(buf), info->addr); ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(03493) "RemoteIPProxyProtocol: optional on %s:%hu", buf, info->addr->port); } for (info = conf->proxy_protocol_disabled; info; info = info->next) { apr_sockaddr_ip_getbuf(buf, sizeof(buf), info->addr); ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(03494) Loading Loading @@ -523,19 +526,11 @@ static int remoteip_modify_request(request_rec *r) protocol handling allowing it to take precedence and return */ if (conn_config) { /* We may have gotten here if processing was optional - check for that */ if (!conn_config->client_addr) { 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; } else { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(03496) "RemoteIPProxyProtocol data is missing, but required! Aborting request."); return HTTP_BAD_REQUEST; } } r->useragent_addr = conn_config->client_addr; r->useragent_ip = conn_config->client_ip; Loading Loading @@ -860,7 +855,7 @@ static int remoteip_hook_pre_connection(conn_rec *c, void *csd) { remoteip_config_t *conf; remoteip_conn_config_t *conn_conf; int optional; int i; /* Do not attempt to manipulate slave connections */ if (c->master != NULL) { Loading @@ -870,13 +865,19 @@ static int remoteip_hook_pre_connection(conn_rec *c, void *csd) conf = ap_get_module_config(ap_server_conf->module_config, &remoteip_module); /* Used twice - do the check only once */ optional = remoteip_addr_in_list(conf->proxy_protocol_optional, c->local_addr); /* check if we're enabled for this connection */ if ((!remoteip_addr_in_list(conf->proxy_protocol_enabled, c->local_addr) && !optional ) 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; } /* We are enabled for this IP/port, but check that we aren't explicitly disabled */ for (i = 0; i < conf->disabled_subnets->nelts; i++) { apr_ipsubnet_t *ip = ((apr_ipsubnet_t**)conf->disabled_subnets->elts)[i]; if (ip && apr_ipsubnet_test(ip, c->client_addr)) return DECLINED; } Loading @@ -898,12 +899,6 @@ static int remoteip_hook_pre_connection(conn_rec *c, void *csd) /* this holds the resolved proxy info for this connection */ conn_conf = apr_pcalloc(c->pool, sizeof(*conn_conf)); /* Propagate the optional flag so the connection handler knows not to abort if the header is mising. NOTE: This means we must check after we read the request that the header was NOT optional, too. */ conn_conf->proxy_protocol_optional = optional; ap_set_module_config(c->conn_config, &remoteip_module, conn_conf); return OK; Loading Loading @@ -1036,31 +1031,20 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, remoteip_parse_status_t psts = HDR_NEED_MORE; const char *ptr; apr_size_t len; apr_size_t this_read = 0; /* Track bytes read in each brigade */ apr_size_t prev_read = 0; if (f->c->aborted) { return APR_ECONNABORTED; } conn_conf = ap_get_module_config(f->c->conn_config, &remoteip_module); /* allocate/retrieve the context that holds our header */ if (!ctx) { ctx = f->ctx = apr_palloc(f->c->pool, sizeof(*ctx)); ctx->rcvd = 0; ctx->need = MIN_HDR_LEN; ctx->version = 0; ctx->mode = AP_MODE_READBYTES; ctx->bb = apr_brigade_create(f->c->pool, f->c->bucket_alloc); ctx->done = 0; if (conn_conf->proxy_protocol_optional) { ctx->mode = AP_MODE_SPECULATIVE; ctx->peeking = 1; } else { ctx->mode = AP_MODE_READBYTES; ctx->peeking = 0; } } if (ctx->done) { Loading @@ -1071,6 +1055,8 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, return ap_get_brigade(f->next, bb_out, mode, block, readbytes); } conn_conf = ap_get_module_config(f->c->conn_config, &remoteip_module); /* try to read a header's worth of data */ while (!ctx->done) { if (APR_BRIGADE_EMPTY(ctx->bb)) { Loading @@ -1084,23 +1070,9 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, return block == APR_NONBLOCK_READ ? APR_SUCCESS : APR_EOF; } if (ctx->peeking) { ctx->rcvd = 0; ctx->need = MIN_HDR_LEN; } while (!ctx->done && !APR_BRIGADE_EMPTY(ctx->bb)) { b = APR_BRIGADE_FIRST(ctx->bb); if (ctx->peeking && APR_BUCKET_IS_EOS(b)) { /* Shortcut - we know no header was found yet and an EOS indicates we never will */ apr_brigade_destroy(ctx->bb); ctx->bb = NULL; ctx->done = 1; return APR_SUCCESS; } ret = apr_bucket_read(b, &ptr, &len, block); if (APR_STATUS_IS_EAGAIN(ret) && block == APR_NONBLOCK_READ) { return APR_SUCCESS; Loading @@ -1112,10 +1084,6 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, memcpy(ctx->header + ctx->rcvd, ptr, len); ctx->rcvd += len; if (ctx->peeking && block == APR_NONBLOCK_READ) { this_read += len; } apr_bucket_delete(b); psts = HDR_NEED_MORE; Loading @@ -1123,37 +1091,8 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, /* reading initial chunk */ if (ctx->rcvd >= MIN_HDR_LEN) { ctx->version = remoteip_determine_version(f->c, ctx->header); /* We've read enough to know that a header is present. In peek mode we purge the bb and can decide to step aside or switch to non-speculative read to consume the data */ if (ctx->peeking) { if (ctx->version < 0) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, APLOGNO(03512) "RemoteIPProxyProtocol: PROXY header is missing from " "request. Stepping aside."); apr_brigade_destroy(ctx->bb); ctx->bb = NULL; ctx->done = 1; return ap_get_brigade(f->next, bb_out, mode, block, readbytes); } else { /* Rest ctx to initial values */ ctx->rcvd = 0; ctx->need = MIN_HDR_LEN; ctx->version = 0; ctx->done = 0; ctx->mode = AP_MODE_READBYTES; ctx->peeking = 0; apr_brigade_cleanup(ctx->bb); ap_get_brigade(f->next, ctx->bb, ctx->mode, block, ctx->need - ctx->rcvd); } } else { if (ctx->version < 0) { psts = HDR_MISSING; psts = HDR_ERROR; } else if (ctx->version == 1) { ctx->mode = AP_MODE_GETLINE; Loading @@ -1164,7 +1103,6 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, } } } } else if (ctx->version == 1) { psts = remoteip_process_v1_header(f->c, conn_conf, (proxy_header *) ctx->header, Loading @@ -1174,7 +1112,6 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, if (ctx->rcvd >= MIN_V2_HDR_LEN) { ctx->need = MIN_V2_HDR_LEN + remoteip_get_v2_len((proxy_header *) ctx->header); } if (ctx->rcvd >= ctx->need) { psts = remoteip_process_v2_header(f->c, conn_conf, Loading @@ -1191,10 +1128,6 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, } switch (psts) { case HDR_MISSING: ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(03510) "RemoteIPProxyProtocol: no valid PROXY header found"); /* fall through to error case */ case HDR_ERROR: f->c->aborted = 1; apr_brigade_destroy(ctx->bb); Loading @@ -1208,18 +1141,6 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, break; } } /* In SPECULATIVE mode, upstream will return all data on each brigade get - even data we've seen. For non blocking read, make sure we got new data or return early when we haven't */ if (ctx->peeking && block == APR_NONBLOCK_READ) { if (this_read == prev_read) { return APR_SUCCESS; } else { prev_read = this_read; } } } /* we only get here when done == 1 */ Loading Loading @@ -1268,8 +1189,11 @@ 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_TAKE1("RemoteIPProxyProtocol", remoteip_enable_proxy_protocol, NULL, RSRC_CONF, "Enable PROXY protocol handling (`on', `off', `optional')"), AP_INIT_FLAG("RemoteIPProxyProtocol", remoteip_enable_proxy_protocol, NULL, RSRC_CONF, "Enable PROXY protocol handling (`on', `off')"), AP_INIT_TAKE_ARGV("RemoteIPProxyProtocolDisableHosts", remoteip_disable_networks, NULL, RSRC_CONF, "Disable PROXY " "protocol handling for this list of networks in CIDR format"), { NULL } }; Loading