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 = {