You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by wr...@apache.org on 2009/03/17 23:55:07 UTC
svn commit: r755437 - in /httpd/sandbox/mod_remoteip: README mod_remoteip.c
Author: wrowe
Date: Tue Mar 17 22:55:07 2009
New Revision: 755437
URL: http://svn.apache.org/viewvc?rev=755437&view=rev
Log:
Process multiple values presented in the RemoteIPHeader request header value
in R-T-L sequence, set aside the consumed headers in remoteip-proxy-ip-list
request note value, and introduce the RemoteIPProxiesHeader directive to
replicate that information as a request header.
Remaining TODO's; optionally filter private subnet addresses and present a
trust list in the configuration.
Modified:
httpd/sandbox/mod_remoteip/README
httpd/sandbox/mod_remoteip/mod_remoteip.c
Modified: httpd/sandbox/mod_remoteip/README
URL: http://svn.apache.org/viewvc/httpd/sandbox/mod_remoteip/README?rev=755437&r1=755436&r2=755437&view=diff
==============================================================================
--- httpd/sandbox/mod_remoteip/README (original)
+++ httpd/sandbox/mod_remoteip/README Tue Mar 17 22:55:07 2009
@@ -19,20 +19,17 @@
field name, such as X-Client-IP, and trust this header, preserving the
advertised X-Forwarded-For value to the application for its evalution.
-
-TODO: the immediate improvement in this module on my plate is to add the
-following processing...
-
Because the proxy may aggregate requests; the connection remote_ip values
-should be reset between keep-alive requests.
+are reset between keep-alive requests if the header changes, or the last
+values are reused for efficiency when the header is unchanged.
The convention is for proxies to append to this header, such that;
X-Forwarded-For: origin-client, proxy1, proxy2
offers a list of these proxies. So starting from the true remote IP address
-reading from R-T-L, for each trusted proxy IP address, we will present the
-immediate parent IP address to the application.
+reading from R-T-L, for each trusted proxy IP address, we present the
+preceeding X-F-F header value as the apparent client IP address.
The context of the trusted IP should be preserved, and the untrusted IP
address preserved in the X-Forwarded-For header. If we treat the true
@@ -46,9 +43,21 @@
X-Forwarded-For: origin-client
-and a request notes field value of;
+and a request notes field value of remoteip-proxy-ip-list containing the
+value of "proxy2, gateway"
+
+This remoteip-proxy-ip-list may be presented as a request header, by using
+the additional directive RemoteIPProxiesHeader, which specifies the header
+field to pass this information on to the application. E.g.
+
+ RemoteIPProxiesHeader X-Forwarded-By
- resolved-forwarded-by: proxy2, gateway
+or whatever desired header field should be used.
+
+
+
+TODO: the immediate improvement in this module on my plate is to add the
+following processing...
However, when using the advertised client IP address, there is absolutely
no trust that the origin of that data. It becomes necessary to build a list
Modified: httpd/sandbox/mod_remoteip/mod_remoteip.c
URL: http://svn.apache.org/viewvc/httpd/sandbox/mod_remoteip/mod_remoteip.c?rev=755437&r1=755436&r2=755437&view=diff
==============================================================================
--- httpd/sandbox/mod_remoteip/mod_remoteip.c (original)
+++ httpd/sandbox/mod_remoteip/mod_remoteip.c Tue Mar 17 22:55:07 2009
@@ -29,13 +29,36 @@
module AP_MODULE_DECLARE_DATA remoteip_module;
typedef struct {
+ /** The header to retrieve a proxy-via ip list */
const char *remoteip_header;
+ /** A header to record the proxied IP's
+ * (removed as the physical connection and
+ * from the proxy-via ip header value list)
+ */
+ const char *remoteip_proxies_header;
} remoteip_config_t;
+typedef struct {
+ /** The previous proxy-via request header value */
+ const char *prior_remote;
+ /** The unmodified original ip and address */
+ const char *orig_ip;
+ apr_sockaddr_t *orig_addr;
+ /** The list of proxy ip's ignored as remote ip's */
+ const char *proxy_ips;
+ /** The remaining list of untrusted proxied remote ip's */
+ const char *proxied_remote;
+ /** The most recetly modified ip and address record */
+ const char *proxied_ip;
+ apr_sockaddr_t proxied_addr;
+} remoteip_conn_t;
+
static void *create_remoteip_server_config(apr_pool_t *p, server_rec *s)
{
- remoteip_config_t *config = apr_palloc(p, sizeof *config);
- config->remoteip_header = NULL;
+ remoteip_config_t *config = apr_pcalloc(p, sizeof *config);
+ /* config->remoteip_header = NULL;
+ * config->remoteip_proxies_header = NULL;
+ */
return config;
}
@@ -47,13 +70,15 @@
remoteip_config_t *config;
config = (remoteip_config_t *) apr_palloc(p, sizeof(*config));
- if (server->remoteip_header)
- config->remoteip_header = server->remoteip_header;
- else
- config->remoteip_header = global->remoteip_header;
+ config->remoteip_header = server->remoteip_header
+ ? server->remoteip_header
+ : global->remoteip_header;
+ config->remoteip_proxies_header = server->remoteip_proxies_header
+ ? server->remoteip_proxies_header
+ : global->remoteip_proxies_header;
return config;
}
-
+
static const char *remoteip_header_set(cmd_parms *cmd, void *dummy,
const char *arg)
{
@@ -63,49 +88,171 @@
return NULL;
}
-static int modify_connection(request_rec *r)
+static const char *remoteip_proxies_header_set(cmd_parms *cmd, void *dummy,
+ const char *arg)
{
- conn_rec *c = r->connection;
- remoteip_config_t *config = ap_get_module_config(r->server->module_config,
+ remoteip_config_t *config = ap_get_module_config(cmd->server->module_config,
&remoteip_module);
- char *remote;
+ config->remoteip_proxies_header = apr_pstrdup(cmd->pool, arg);
+ return NULL;
+}
- if (!config->remoteip_header)
- return OK;
+static int remoteip_modify_connection(request_rec *r)
+{
+ conn_rec *c = r->connection;
+ remoteip_config_t *config = (remoteip_config_t *)
+ ap_get_module_config(r->server->module_config, &remoteip_module);
+ remoteip_conn_t *conn;
+#ifdef REMOTEIP_OPTIMIZED
+ apr_sockaddr_t temp_sa_buff;
+ apr_sockaddr_t *temp_sa = &temp_sa_buff;
+#else
+ apr_sockaddr_t *temp_sa;
+#endif
+ apr_status_t rv;
+ char *remote = (char *) apr_table_get(r->headers_in, config->remoteip_header);
+ char *proxy_ips = NULL;
+ char *parse_remote;
+ char *eos;
+
+ apr_pool_userdata_get(&conn, "mod_remoteip-conn", c->pool);
+
+ if (conn) {
+ if (remote && (strcmp(remote, conn->prior_remote) == 0)) {
+ /* TODO: Recycle r-> overrides from previous request
+ */
+ goto ditto_request_rec;
+ }
+ else {
+ /* TODO: Revert connection from previous request
+ */
+ c->remote_addr = conn->orig_addr;
+ c->remote_ip = (char *) conn->orig_ip;
+ }
+ }
- remote = (char*)apr_table_get(r->headers_in, config->remoteip_header);
if (!remote)
return OK;
- /* Decode remote_addr - sucks; apr_sockaddr_vars_set isn't 'public' */
- if (inet_pton(AF_INET, remote,
- &c->remote_addr->sa.sin.sin_addr) > 0) {
- apr_sockaddr_vars_set(c->remote_addr, APR_INET, 0);
- }
+ remote = apr_pstrdup(r->pool, remote);
+
+#ifdef REMOTEIP_OPTIMIZED
+ memcpy(&temp_sa, c->remote_addr, sizeof(temp_sa));
+ temp_sa->pool = r->pool;
+#else
+ temp_sa = c->remote_addr;
+#endif
+
+ while (remote) {
+
+ /* TODO: verify c->remote_ip is trusted
+ */
+
+ if ((parse_remote = strrchr(remote, ',')) == NULL) {
+ parse_remote = remote;
+ remote = NULL;
+ }
+ else {
+ *(parse_remote++) = '\0';
+ }
+
+ while (*parse_remote == ' ')
+ ++parse_remote;
+
+ eos = parse_remote + strlen(parse_remote) - 1;
+ while (eos >= parse_remote && *eos == ' ')
+ *(eos--) = '\0';
+
+ if (eos < parse_remote) {
+ if (remote)
+ *(remote + strlen(remote)) = ',';
+ else
+ remote = parse_remote;
+ break;
+ }
+
+#ifdef REMOTEIP_OPTIMIZED
+ /* Decode remote_addr - sucks; apr_sockaddr_vars_set isn't 'public' */
+ if (inet_pton(AF_INET, parse_remote,
+ &temp_sa_buff->sa.sin.sin_addr) > 0) {
+ apr_sockaddr_vars_set(temp_sa, APR_INET, temp_sa.port);
+ }
#if APR_HAVE_IPV6
- else if (inet_pton(AF_INET6, remote,
- &c->remote_addr->sa.sin6.sin6_addr) > 0) {
- apr_sockaddr_vars_set(c->remote_addr, APR_INET6, 0);
- }
+ else if (inet_pton(AF_INET6, parse_remote,
+ &temp_sa->sa.sin6.sin6_addr) > 0) {
+ apr_sockaddr_vars_set(temp_sa, APR_INET6, temp_sa.port);
+ }
+ else {
+ rv = apr_get_netos_error();
#endif
- else {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, apr_get_netos_error(), r,
- "Header %s value of %s doesn't appear to be a client IP",
- config->remoteip_header, remote);
- return OK;
+#else /* !REMOTEIP_OPTIMIZED */
+ /* We map as IPv4 rather than IPv6 for equivilant host names
+ * or IPV4OVERIPV6
+ */
+ rv = apr_sockaddr_info_get(&temp_sa, parse_remote,
+ APR_UNSPEC, temp_sa->port,
+ APR_IPV4_ADDR_OK, r->pool);
+ if (rv != APR_SUCCESS) {
+#endif
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
+ "Header %s value of %s doesn't appear to be a client IP",
+ config->remoteip_header, parse_remote);
+ if (remote)
+ *(remote + strlen(remote)) = ',';
+ else
+ remote = parse_remote;
+ break;
+ }
+
+ if (!conn) {
+ conn = (remoteip_conn_t *) apr_palloc(c->pool, sizeof(*conn));
+ apr_pool_userdata_set(conn, "mod_remoteip-conn", NULL, c->pool);
+ conn->orig_addr = c->remote_addr;
+ conn->orig_ip = c->remote_ip;
+ }
+
+ /* Set remote_ip string */
+ if (proxy_ips)
+ proxy_ips = apr_pstrcat(r->pool, proxy_ips, ", ", c->remote_ip, NULL);
+ else
+ proxy_ips = c->remote_ip;
+
+ c->remote_addr = temp_sa;
+ apr_sockaddr_ip_get(&c->remote_ip, c->remote_addr);
}
- /* Set remote_ip string */
- remote = apr_pstrdup(c->pool, remote);
- c->remote_ip = remote;
+ /* Fixups here, remote becomes Via, etc */
+
+ if (!proxy_ips)
+ return OK;
+
+ c->remote_ip = apr_pstrdup(c->pool, c->remote_ip);
+
+ conn->proxied_ip = c->remote_ip;
+ memcpy(&conn->proxied_addr, &temp_sa, sizeof(temp_sa));
+ conn->proxied_addr.pool = c->pool;
+ conn->proxied_remote = apr_pstrdup(c->pool, remote);
+ conn->prior_remote = apr_pstrdup(c->pool, apr_table_get(r->headers_in, config->remoteip_header));
+ conn->proxy_ips = apr_pstrdup(c->pool, proxy_ips);
+
+ c->remote_addr = &conn->proxied_addr;
/* Unset remote_host string DNS lookups */
c->remote_host = NULL;
c->remote_logname = NULL;
+ditto_request_rec:
+ if (conn->proxied_remote)
+ apr_table_setn(r->headers_in, config->remoteip_header, conn->proxied_remote);
+ else
+ apr_table_unset(r->headers_in, config->remoteip_header);
+ apr_table_setn(r->notes, "remoteip-proxy-ip-list", conn->proxy_ips);
+ if (config->remoteip_proxies_header)
+ apr_table_setn(r->headers_in, config->remoteip_proxies_header, conn->proxy_ips);
+
ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r,
- "Using header %s value %s as client's IP",
- config->remoteip_header, remote);
+ "Using %s as client's IP by proxies %s",
+ conn->proxied_ip, conn->proxy_ips);
return OK;
}
@@ -113,12 +260,14 @@
{
AP_INIT_TAKE1("RemoteIPHeader", remoteip_header_set, NULL, RSRC_CONF,
"Specifies a request header to trust as the client IP, e.g. X-Forwarded-For."),
+ AP_INIT_TAKE1("RemoteIPProxiesHeader", remoteip_proxies_header_set, NULL, RSRC_CONF,
+ "Specifies a request header record proxy IP's; if not given then do not record."),
{ NULL }
};
static void register_hooks(apr_pool_t *p)
{
- ap_hook_post_read_request(modify_connection, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_post_read_request(remoteip_modify_connection, NULL, NULL, APR_HOOK_FIRST);
}
module AP_MODULE_DECLARE_DATA remoteip_module = {