head	1.1;
access;
symbols;
locks; strict;
comment	@# @;


1.1
date	2012.12.24.13.11.14;	author svnexp;	state Exp;
branches;
next	;


desc
@@


1.1
log
@## SVN ## Exported commit - http://svnweb.freebsd.org/changeset/base/309457
## SVN ## CVS IS DEPRECATED: http://wiki.freebsd.org/CvsIsDeprecated
## SVN ##
## SVN ## ------------------------------------------------------------------------
## SVN ## r309457 | kuriyama | 2012-12-24 12:42:56 +0000 (Mon, 24 Dec 2012) | 2 lines
## SVN ##
## SVN ## Add option to patch for IPv6 address support.
## SVN ##
## SVN ## ------------------------------------------------------------------------
## SVN ##
@
text
@# $FreeBSD: head/www/mod_extract_forwarded/files/extra-patch-yoshfuji 309457 2012-12-24 12:42:56Z kuriyama $
diff --git a/INSTALL b/INSTALL
index fa06d8a..d1f6d56 100644
--- a/INSTALL
+++ b/INSTALL
@@@@ -13,11 +13,12 @@@@ to build and install a DSO version of the module:
 
 /usr/local/apache2/bin/apxs -c -i -a mod_extract_forwarded.c
 
-If the Apache instance you are adding mod_extract_forwarded to will not
-have mod_proxy and proxy_http loaded then you will get an error when
-mod_extract_forwarded is loaded. In that case edit
-mod_extract_forwarded.c and comment out the #define for
-USING_proxy_http_module or change it to an an #undef. If you
-subsequently run Apache with proxy_http do not forget to reinstate the
-#define; failure to do so will mean that any X-Fowarded-For header
-inserted by proxy_http will use the spoofed IP number in error.
+If the Apache instance you are adding mod_extract_forwarded to will
+have mod_proxy and proxy_http loaded then you need to build and
+install a DSO version of the module:
+
+/usr/local/apache2/bin/apxs -c -i -a mod_extract_forwarded_proxy.c
+
+Without this module, any X-Fowarded-For header inserted by proxy_http
+will use the spoofed IP number.
+
diff --git a/mod_extract_forwarded.c b/mod_extract_forwarded.c
index afecbcf..fa94493 100644
--- a/mod_extract_forwarded.c
+++ b/mod_extract_forwarded.c
@@@@ -84,6 +84,9 @@@@
  *    of what is done by the module as an aid to understanding fixing problems
  *    with this code; this is NOT for production use because of the volume of
  *    output it will generate and the way it flushes stderr
+ * 8. Support IPv6: If real connection is served by IPv6 socket, both IPv4 and
+ *    IPv6 clients are supported.  If real connection is served by IPv4 socket,
+ *    only IPv4 clients are supported.  [yoshfuji]
  * 
  * History of Apache 2 compatible mod_extract_forwarded
  * ----------------------------------------------------
@@@@ -98,7 +101,8 @@@@
  *                              Cleaned up interpretation of per_der_config 
  *                              for internal redirect and subrequests and 
  *                              other logic tidying
- *
+ *             12 Apr 2009      Apache 2.2 support. [yoshfuji]
+ *             16 Apr 2009      IPv6 support. [yoshfuji]
  */
 
 #include "httpd.h"
@@@@ -110,22 +114,13 @@@@
 #include "http_request.h"
 #include "util_script.h"
 #include "http_connection.h"
-#include "mod_proxy.h"
 #include "apr_strings.h"
 
 #include <netdb.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
 
-/* 
- * #define USING_proxy_http_module if proxy_http.c module is either 
- * compiled into Apache 2 or it is being loaded as a DSO. If proxy_http.c 
- * module is not loaded then this module will generate an error when and
- * if it is loaded as a DSO. In that case comment out the #define, recompile
- * and reinstall this module. BUT do not forget to change things back if
- * proxy_http.c module is reinstated
- */
-#define USING_proxy_http_module 1 
+#include "mod_extract_forwarded.h"
 
 /*--------------------------------------------------------------------------*/
 /*                                                                          */
@@@@ -139,17 +134,6 @@@@
  */
 module AP_MODULE_DECLARE_DATA extract_forwarded_module;
 
-/*
- * Per directory configuration record.  
- */
-typedef struct {
-    int order;  /* order in which the accept and refuse specs are applied */
-    int debug;                      /* debug output to error log flag */
-    const char *envar;              /* name of env var to add */
-    apr_table_t *accept_proxies;    /* proxies to trust */
-    apr_table_t *refuse_proxies;    /* proxies to distrust */
-} mef_config;
-
 /* 
  * Two possible orders in which the accept and refuse specs are applied
  */
@@@@ -279,72 +263,41 @@@@ static const char *mef_debug_control(cmd_parms *cparms, void *mconfig,
 }
 
 /* 
- * Given an IP or 'all' as "arg", add it to the accept_proxies table
+ * Given an IP or 'all' as "arg", add it to the accept_proxies/refuse_proxies
+ * table
  */
-static const char *mef_accept_proxy(cmd_parms *cparms, void *mconfig, 
+static const char *mef_config_proxy(cmd_parms *cparms, void *mconfig, 
                                     const char *arg) 
 {
     mef_config *conf = (mef_config *)mconfig;
-    struct hostent *hptr = NULL;
-    char** haddr;
+    apr_table_t *conf_proxies = cparms->info ?
+                                conf->accept_proxies : conf->refuse_proxies;
     if (strcasecmp(arg, "all") == 0)
     /* "all" keyword replaces everything with just itself */
     {
-        apr_table_clear(conf->accept_proxies);
-        apr_table_set(conf->accept_proxies, arg, "t");
+        apr_table_clear(conf_proxies);
+        apr_table_set(conf_proxies, arg, "t");
     } 
     else 
-    /* Add IP to list of accepted proxies */
+    /* Add IP to list of accepted/refuse proxies */
     {
-        hptr = gethostbyname(arg);
-        if (hptr) 
+        apr_sockaddr_t *sa0, *sa;
+        if (apr_sockaddr_info_get(&sa0, arg, APR_UNSPEC, 0, 0,
+                                  cparms->temp_pool) == APR_SUCCESS)
         {
-            apr_table_unset(conf->accept_proxies, "all");
-            for (haddr=hptr->h_addr_list; *haddr; haddr++)
+            apr_table_unset(conf_proxies, "all");
+            for (sa = sa0; sa; sa = sa->next)
             {
-                apr_table_set(conf->accept_proxies, 
-                              inet_ntoa(*((struct in_addr*)(*haddr))), "t");
+                char *ipaddr;
+                if (apr_sockaddr_ip_get(&ipaddr, sa) == APR_SUCCESS)
+                {
+                    apr_table_set(conf_proxies, ipaddr, "t");
+                }
             }
-        } 
-        else
-        {
-            return "No 'all' or valid IP identified by MEFaccept";
         }
-    }
-    return NULL;
-}
-
-/* 
- * Given an IP or 'all' as "arg", add it to the refused_proxies table
- */
-static const char *mef_refuse_proxy(cmd_parms *cparms, void *mconfig,
-                                    const char *arg)
-{
-    mef_config *conf = (mef_config *) mconfig;
-    struct hostent *hptr = NULL;
-    char** haddr;
-    if (strcasecmp(arg, "all") == 0) 
-    /* "all" keyword replaces everything with just itself */
-    {
-        apr_table_clear(conf->refuse_proxies);
-        apr_table_set(conf->refuse_proxies, arg, "t");
-    } 
-    else 
-    /* Add IP to list of refused proxies */
-    {
-        hptr = gethostbyname(arg);
-        if (hptr) 
-        {
-            apr_table_unset(conf->refuse_proxies, "all");
-            for (haddr=hptr->h_addr_list; *haddr; haddr++)
-            {
-                apr_table_set(conf->refuse_proxies,
-                              inet_ntoa(*((struct in_addr*)(*haddr))), "t");
-            }
-        } 
-        else 
+        else
         {
-            return "No 'all' or valid IP identified by MEFrefuse";
+            return "No 'all' or valid IP identified by MEFaccept / MEFrefuse";
         }
     }
     return NULL;
@@@@ -385,54 +338,6 @@@@ static int acceptable_proxy(mef_config *conf, char *proxy_ip)
     return 0;
 }
 
-/* 
- * The MEFsave_rec data structure is used to preserve information that
- * this module has modified in the conn_rec associated with a request
- * so that the conn_rec can be restored to its original state as needed.
- * It also carries information between transaction phases and internal
- * redirects and subrequests
- */
-typedef struct MEFsave_rec MEFsave_rec;
-
-struct MEFsave_rec {
-    conn_rec *connection;           /* connection record being used */
-    in_addr_t orig_in_addr;         /* original remote in_addr_t */ 
-    in_addr_t new_in_addr;          /* modified remote in_addr_t */ 
-    char *orig_remote_ip;           /* original remote_ip */
-    char *new_remote_ip;            /* modified remote_ip */
-    int conn_rec_mod_state;         /* conn_rec modification state */
-    int debug;                      /* are we printing MEF debug */
-    const char *envar;              /* name of env var to add */
-    void *per_dir_config;           /* per_dir_config applicable */
-    MEFsave_rec *other_saved;       /* any preceding req's save_rec */
-    request_rec *other_r;           /* any preceding req's request_rec */    
-};
-
-#define CONN_REC_MODIFIED 1
-#define CONN_REC_RESTORED 0
-
-/*
- * remote_in_addr returns a pointer to the in_addr_t which specifes
- * the IP of the remote end of the connection supporting the specified
- * request. NULL is returned if this cannot be determined.
- */
-static in_addr_t *get_remote_in_addr(conn_rec *conn)
-{
-    in_addr_t *result = NULL;
-    if (conn->remote_addr->family == AF_INET)
-    {
-        result = &(conn->remote_addr->sa.sin.sin_addr.s_addr);
-    }
-#if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED)
-    if (conn->remote_addr->family == AF_INET6 &&
-        IN6_IS_ADDR_V4MAPPED(&conn->remote_addr->sa.sin6.sin6_addr)) 
-    {
-        result = &(((uint32_t *)conn->remote_addr->ipaddr_ptr)[3]);
-    }
-#endif
-    return result;
-}
-
 /* Forward declared for convenience */
 static apr_status_t cleanup_initial(void *data);
 static apr_status_t cleanup_not_initial(void *data);
@@@@ -446,22 +351,12 @@@@ static apr_status_t cleanup_not_initial(void *data);
  */
 static int spoof_initial(request_rec *r, char *spoof_ip, char *phase)
 {
-    in_addr_t *remote_in_addr;
     MEFsave_rec *saved;
     mef_config *conf = ap_get_module_config(r->per_dir_config, 
                                             &extract_forwarded_module);
-    /* Validate and acquire pointer to the remote in_addr_t */
-    if ((remote_in_addr = get_remote_in_addr(r->connection)) == NULL)
-    {
-        /* Could not get a valid value so give up */
-        if (conf->debug == MEF_DEBUG_ON) 
-        {
-            fprintf(stderr,"MEF: phase:%s, si problem acquiring remote_in_addr\n", 
-                    phase);
-            fflush(stderr);
-        }
-        return DECLINED;
-    }
+    apr_sockaddr_t *sa;
+    apr_port_t port;
+
     /*
      * We can proceed to do the spoof
      *
@@@@ -470,9 +365,40 @@@@ static int spoof_initial(request_rec *r, char *spoof_ip, char *phase)
     saved = apr_pcalloc(r->pool, sizeof(MEFsave_rec));
     /* Then the saving */
     saved->connection = r->connection;
-    saved->orig_in_addr = *remote_in_addr;
+    saved->orig_addr = *r->connection->remote_addr;
     saved->orig_remote_ip = r->connection->remote_ip;
-    saved->new_in_addr = inet_addr(spoof_ip);
+
+    /* setup new address
+     * it's easy if address family is not changed.
+     */
+    port = r->connection->remote_addr->port;
+    if (apr_sockaddr_info_get(&sa, spoof_ip,
+                              r->connection->remote_addr->family, port,
+                              0, r->pool) != APR_SUCCESS)
+    {
+#if APR_HAVE_IPV6
+        /* Try inter-family conversion.
+         * If if the real connection is served via ipv4, it
+         * implies   Give up if connection is ipv4 and real client is ipv6.
+         */
+        char *buf;
+        if (r->connection->remote_addr->family != APR_INET6)
+        {
+            return DECLINED;
+        }
+        buf = apr_palloc(r->pool, strlen(spoof_ip) + sizeof("::ffff:"));
+	sprintf(buf, "::ffff:%s", spoof_ip);
+        if (apr_sockaddr_info_get(&sa, buf, APR_INET6, port,
+                                  0, r->pool) != APR_SUCCESS)
+        {
+            return DECLINED;
+        }
+#else
+        return DECLINED;
+#endif
+    }
+
+    saved->new_addr = *sa;
     saved->new_remote_ip = spoof_ip;
     saved->per_dir_config = r->per_dir_config;
     saved->debug = conf->debug;
@@@@ -480,7 +406,7 @@@@ static int spoof_initial(request_rec *r, char *spoof_ip, char *phase)
     saved->other_saved = NULL;
     saved->other_r = NULL;
     /* Then the modifying of the conn_rec */
-    *remote_in_addr = saved->new_in_addr;
+    *saved->connection->remote_addr = saved->new_addr;
     saved->connection->remote_ip = saved->new_remote_ip;
     saved->conn_rec_mod_state = CONN_REC_MODIFIED;
     /* Force re-evaluation of the remote_host value */
@@@@ -520,7 +446,6 @@@@ static int spoof_initial(request_rec *r, char *spoof_ip, char *phase)
 static int spoof_not_initial(request_rec *this_r, request_rec *other_r,
                              char *phase)
 {
-    in_addr_t *remote_in_addr;
     MEFsave_rec *saved;
     MEFsave_rec *other_saved;
     /* 
@@@@ -540,10 +465,9 @@@@ static int spoof_not_initial(request_rec *this_r, request_rec *other_r,
     saved = apr_pcalloc(this_r->pool, sizeof(MEFsave_rec));
     /* Then the copying */
     saved->connection = other_saved->connection;
-    remote_in_addr = get_remote_in_addr(saved->connection);
-    saved->orig_in_addr = other_saved->orig_in_addr;
+    saved->orig_addr = other_saved->orig_addr;
     saved->orig_remote_ip = other_saved->orig_remote_ip;
-    saved->new_in_addr = other_saved->new_in_addr;
+    saved->new_addr = other_saved->new_addr;
     saved->new_remote_ip = other_saved->new_remote_ip;
     saved->per_dir_config = other_saved->per_dir_config;
     saved->debug = other_saved->debug;
@@@@ -552,7 +476,11 @@@@ static int spoof_not_initial(request_rec *this_r, request_rec *other_r,
     saved->other_saved = other_saved;
     saved->other_r = other_r;
     /* Ensure the conn_rec is spoofed */
-    *remote_in_addr = saved->new_in_addr;
+    if (saved->connection->remote_addr->family != saved->new_addr.family)
+    {
+        return DECLINED;
+    }
+    *saved->connection->remote_addr = saved->new_addr;
     this_r->connection->remote_ip = saved->new_remote_ip;
     saved->conn_rec_mod_state = CONN_REC_MODIFIED;
     /* Force re-evaluation of the remote_host value */
@@@@ -589,16 +517,11 @@@@ static int spoof_not_initial(request_rec *this_r, request_rec *other_r,
  * The undo_spoof() function undoes the changes made to a conn_rec 
  * by spoof_initial() or spoof_not_initial()
  */
-static int undo_spoof(MEFsave_rec *saved, request_rec *r, char *phase)
+int extract_forwarded_undo_spoof(MEFsave_rec *saved, request_rec *r,
+                                 char *phase)
 {
-    in_addr_t *remote_in_addr;
-    if ((remote_in_addr = get_remote_in_addr(saved->connection)) == NULL)
-    {
-        /* Could not get a valid value so give up */
-        return DECLINED;
-    }
     /* Do the restoring */
-    *remote_in_addr = saved->orig_in_addr;
+    *saved->connection->remote_addr = saved->orig_addr;
     saved->connection->remote_ip = saved->orig_remote_ip;
     saved->connection->remote_host = NULL;
     ap_get_remote_host(saved->connection, saved->per_dir_config, 
@@@@ -641,16 +564,11 @@@@ static int undo_spoof(MEFsave_rec *saved, request_rec *r, char *phase)
  *    subordinate, request_rec which is (should be) using the same
  *    conn_rec as the primary request
  */
-static int redo_spoof(MEFsave_rec *saved, request_rec *r, char *phase)
+int extract_forwarded_redo_spoof(MEFsave_rec *saved, request_rec *r,
+                                 char *phase)
 {
-    in_addr_t *remote_in_addr;
-    if ((remote_in_addr = get_remote_in_addr(saved->connection)) == NULL)
-    {
-        /* Could not get a valid value so give up */
-        return DECLINED;
-    }
     /* Modify it all again */
-    *remote_in_addr = saved->new_in_addr;
+    *saved->connection->remote_addr = saved->new_addr;
     saved->connection->remote_ip = saved->new_remote_ip;
     saved->connection->remote_host = NULL;
     ap_get_remote_host(saved->connection, saved->per_dir_config, 
@@@@ -704,7 +622,7 @@@@ static int redo_spoof(MEFsave_rec *saved, request_rec *r, char *phase)
 static int cleanup_initial(void *data)
 {
     MEFsave_rec *saved = (MEFsave_rec *)data;
-    return undo_spoof(saved, NULL, "cleanup initial"); 
+    return extract_forwarded_undo_spoof(saved, NULL, "cleanup initial"); 
 }
 
 static int cleanup_not_initial(void *data)
@@@@ -712,13 +630,15 @@@@ static int cleanup_not_initial(void *data)
     MEFsave_rec *saved = (MEFsave_rec *)data;
     if (saved->other_saved->conn_rec_mod_state == CONN_REC_MODIFIED) 
     {
-        return redo_spoof(saved->other_saved, saved->other_r, 
-                          "cleanup not initial");
+        return extract_forwarded_redo_spoof(saved->other_saved,
+                                            saved->other_r,
+                                            "cleanup not initial");
     }
     else
     {
-        return undo_spoof(saved->other_saved, saved->other_r,
-                          "cleanup not initial");    
+        return extract_forwarded_undo_spoof(saved->other_saved,
+                                            saved->other_r,
+                                            "cleanup not initial");    
     }
 }
 
@@@@ -758,7 +678,7 @@@@ static int primary_request(request_rec *r, char *phase)
     {
         if (conf->debug == MEF_DEBUG_ON) 
         {
-            fprintf(stderr,"MEF: phase:%s, $s not acceptabler proxy, %s\n", 
+            fprintf(stderr,"MEF: phase:%s, %s not acceptabler proxy, %s\n", 
                     phase, conn->remote_ip, r->unparsed_uri);
             fflush(stderr);
         }
@@@@ -917,66 +837,6 @@@@ static int mef_access_check(request_rec *r)
     return mef_composite(r, "access check");
 }
 
-/*
- * mef_before_proxy_http() is called if Apache 2's HTTP proxy_http handler
- * is about to act and undoes the spoofing of the conn_rec associated with
- * the incoming request if the proxy is about to add information to the
- * request's X-Forwarded-For header. Without this the wrong IP (the
- * spoof one) is added to the X-Forwarded-For header.
- */
-static int mef_before_proxy_http(request_rec *r, 
-                                 proxy_server_conf *pconf,
-                                 char *url, const char *proxyname, 
-                                 apr_port_t proxyport)
-{
-    MEFsave_rec *saved;
-    /*
-     * If our post-read-request handler did something we may have to too 
-     */
-    if ((saved = (MEFsave_rec *)ap_get_module_config(r->request_config, 
-                                         &extract_forwarded_module)) != NULL)
-    {
-        /*
-         * If proxy_http is going to add X-Forwarded-For info then we have
-         * have to undo the changes we made earlier so proxy_http can get 
-         * it right
-         */
-        if (PROXYREQ_REVERSE == r->proxyreq) 
-        {
-            undo_spoof(saved,  r, "before proxy http");
-        }
-    }
-    return DECLINED;
-}
-
-/*
- * mef_logging() is used to redo the spoofing of the conn_rec associated
- * with the incoming request if was undone.
- * Redoing the spoof is to ensure that the spoof IP is used for logging 
- * information about the request
- */
-static int mef_logging(request_rec *r)
-{
-    MEFsave_rec *saved;
-    /*
-     * If our post-read-request handler did something we may have to too 
-     */
-    if ((saved = (MEFsave_rec *)ap_get_module_config(r->request_config, 
-                                         &extract_forwarded_module)) != NULL)
-    {
-        /*
-         * If we undid the spoof, probably because proxy_http was adding 
-         * X-Forwarded-For info, then we want to redo the changes we
-         * undid so the spook IP is logged
-         */
-        if (saved->conn_rec_mod_state == CONN_REC_RESTORED) 
-        {
-            redo_spoof(saved, r, "logging");
-        }
-    }
-    return DECLINED;
-}
-
 /*--------------------------------------------------------------------------*/
 /*                                                                          */
 /* Data structures pulling all the mef module's bits together               */
@@@@ -996,16 +856,6 @@@@ static void mef_register_hooks(apr_pool_t *p)
  *    ap_hook_header_parser(mef_header_parser, NULL, NULL, APR_HOOK_FIRST);
  */
     ap_hook_access_checker(mef_access_check, NULL, NULL, APR_HOOK_FIRST);   
-#ifdef USING_proxy_http_module
-    /* 
-     * Only need to register the following handlers if proxy_http_module
-     * is going to be loaded
-     */
-    static const char *const mef_proxy_b4[] = { "proxy_http.c", NULL };
-    proxy_hook_scheme_handler(mef_before_proxy_http, NULL, mef_proxy_b4,
-                              APR_HOOK_FIRST);
-    ap_hook_log_transaction(mef_logging, NULL, NULL, APR_HOOK_FIRST);
-#endif /* USING_proxy_http_module */
 }
 
 /* 
@@@@ -1015,6 +865,8 @@@@ static void mef_register_hooks(apr_pool_t *p)
  * translation and hence directory information is unavailable for the 
  * request.
  */
+static char its_an_accept;
+
 static const command_rec mef_cmds[] =
 {
     AP_INIT_TAKE1(
@@@@ -1043,15 +895,15 @@@@ static const command_rec mef_cmds[] =
     ),
     AP_INIT_ITERATE(
         "MEFaccept",            /* directive name */
-        mef_accept_proxy,       /* config action routine */
-        NULL,                   /* argument to include in call */
+        mef_config_proxy,       /* config action routine */
+        &its_an_accept,         /* argument to include in call */
         RSRC_CONF,              /* where available */
                                 /* description  */
         "One or more proxy names or IPs to accept, or 'all'" 
     ),
     AP_INIT_ITERATE(
         "MEFrefuse",            /* directive name */
-        mef_refuse_proxy,       /* config action routine */
+        mef_config_proxy,       /* config action routine */
         NULL,                   /* argument to include in call */
         RSRC_CONF,              /* where available */
                                 /* description  */
diff --git a/mod_extract_forwarded.conf b/mod_extract_forwarded.conf
new file mode 100644
index 0000000..b5606a5
--- /dev/null
+++ b/mod_extract_forwarded.conf
@@@@ -0,0 +1,52 @@@@
+<IfModule mod_extract_forwarded.c>
+	# MEForder:
+	#	This can have either of two value 'refuse,accept' or
+	#	'accept,refuse' and specifies the order in which the
+	#	information in two associated directives, MEFaccept
+	#	and MEFrefuse, are intepreted. The MEFaccept and
+	#	MEFrefuse directives are each used to spcifiy one or
+	#	more IP numbers.
+	MEForder refuse,accept
+
+	# MEFrefuse:
+	#	This can be 'all' OR a space separated list of IP numbers
+	#	and/or domain names of trusted proxy servers whose IP number
+	#	can be derived by DNS from the domain name. The presence of
+	#	'all' overrides any particular IP numbers and means
+	#	that no proxy servers are to be trusted. Individual IP
+	#	numbers mean that those the proxy servers having them
+	#	are not to be trusted. This defaults to 'all'.
+	MEFrefuse all
+
+	# MEFaccept:
+	#	This can be 'all' OR a space separated list of IP numbers
+	#	and/or domain names of trusted proxy servers whose IP number
+	#	can be derived by DNS from the domain name. The presence of
+	#	'all' overrides any particular IP numbers and means
+	#	that all proxy servers are to be trusted. Individual IP
+	#	numbers mean that those the proxy servers having them
+	#	are to be trusted. This defaults to an empty list of
+	#	trusted IP numbers.
+	# MEFaccept <trusted proxy servers' IP numbers>
+
+	# MEFaddenv:
+	#	This can be 'off', 'on' (the default) or a string. 'off'
+	#	means that when spoofing, do not add an environment variable
+	#	whose value is the IP number of the connecting machine.
+	#	'on' means that when spoofing, add an environment variable
+	#	called 'MEF_RPROXY_ADDR' whose value is the IP number of the
+	#	connecting machine. A string means that when spoofing, add
+	#	an environment variable named by the string supplied whose
+	#	value is the IP number of the connecting machine.
+
+	# MEFdebug:
+	#	This can be 'on' or 'off' (the default). When turned 'on'
+	#	information about how the mod_extract_forwarded module is
+	#	processing every request to your Apache 2 server, and any
+	#	associated internal redirects or subsrequests, is written
+	#	to the server's error_log. Thhe amount of output written
+	#	and the way it is generated is such that you would never
+	#	normally want to turn this feature on. This feature is
+	#	intended for debugging operation of the mod_extract_forwarded
+	#	mod_module and it is unlikely you will want to do that.
+</IfModule>
diff --git a/mod_extract_forwarded.h b/mod_extract_forwarded.h
new file mode 100644
index 0000000..96b49a1
--- /dev/null
+++ b/mod_extract_forwarded.h
@@@@ -0,0 +1,131 @@@@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+#ifndef MOD_EXTRACT_FORWARDED_H
+#define MOD_EXTRACT_FORWARDED_H
+
+#include "mod_proxy.h"
+#include "mod_extract_forwarded.h"
+
+extern module AP_MODULE_DECLARE_DATA extract_forwarded_module;
+
+/*
+ * Per directory configuration record.  
+ */
+typedef struct {
+    int order;  /* order in which the accept and refuse specs are applied */
+    int debug;                      /* debug output to error log flag */
+    const char *envar;              /* name of env var to add */
+    apr_table_t *accept_proxies;    /* proxies to trust */
+    apr_table_t *refuse_proxies;    /* proxies to distrust */
+} mef_config;
+
+/* 
+ * Two possible orders in which the accept and refuse specs are applied
+ */
+#define REFUSE_THEN_ACCEPT 0
+#define ACCEPT_THEN_REFUSE 1
+
+/*
+ * To output debug info to error log or not
+ */
+#define MEF_DEBUG_OFF 0
+#define MEF_DEBUG_ON 1
+
+/*
+ * Maximum number of IPs in an X-Forwarded-For header of a request before 
+ * it is treated a excessive and hence absurd
+ */
+#define MEF_ABSURD_PROXY_LIMIT 32
+/*
+ * Default environment variable name
+ */
+#define MEF_PROXY_ADDR "MEF_PROXY_ADDR"
+
+/* 
+ * The MEFsave_rec data structure is used to preserve information that
+ * this module has modified in the conn_rec associated with a request
+ * so that the conn_rec can be restored to its original state as needed.
+ * It also carries information between transaction phases and internal
+ * redirects and subrequests
+ */
+typedef struct MEFsave_rec MEFsave_rec;
+
+struct MEFsave_rec {
+    conn_rec *connection;           /* connection record being used */
+    apr_sockaddr_t orig_addr;       /* original remote address */
+    apr_sockaddr_t new_addr;        /* modified remote address */
+    char *orig_remote_ip;           /* original remote_ip */
+    char *new_remote_ip;            /* modified remote_ip */
+    int conn_rec_mod_state;         /* conn_rec modification state */
+    int debug;                      /* are we printing MEF debug */
+    const char *envar;              /* name of env var to add */
+    void *per_dir_config;           /* per_dir_config applicable */
+    MEFsave_rec *other_saved;       /* any preceding req's save_rec */
+    request_rec *other_r;           /* any preceding req's request_rec */    
+};
+
+#define CONN_REC_MODIFIED 1
+#define CONN_REC_RESTORED 0
+
+/*
+ * Functions provided by mod_extract_forwarded
+ */
+extern int extract_forwarded_undo_spoof(MEFsave_rec *saved, request_rec *r,
+                                        char *phase);
+extern int extract_forwarded_redo_spoof(MEFsave_rec *saved, request_rec *r,
+                                        char *phase);
+
+#endif
diff --git a/mod_extract_forwarded_proxy.c b/mod_extract_forwarded_proxy.c
new file mode 100644
index 0000000..1b53d36
--- /dev/null
+++ b/mod_extract_forwarded_proxy.c
@@@@ -0,0 +1,175 @@@@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+#include "mod_proxy.h"
+
+#include "mod_extract_forwarded.h"
+
+/* 
+ * The undo_spoof() function undoes the changes made to a conn_rec by
+ * spoof_initial() or spoof_not_initial()
+ */
+extern int extract_forwarded_undo_spoof(MEFsave_rec *saved, request_rec *r,
+                                        char *phase);
+
+/* 
+ * The redo_spoof() function reapplies the changes made to a 
+ * conn_rec by spoof_initial() or spoof_not_initial():
+ *
+ * 1. after a prior call to undo_spoof has removed them, typically
+ *    because of proxy_http reverse-proxy X-Forwarded-For issue
+ * 2. when an internal redirect or subrequest has generated a new
+ *    subordinate, request_rec which is (should be) using the same
+ *    conn_rec as the primary request
+ */
+extern int extract_forwarded_redo_spoof(MEFsave_rec *saved, request_rec *r,
+                                        char *phase);
+
+/*
+ * mef_before_proxy_http() is called if Apache 2's HTTP proxy_http handler
+ * is about to act and undoes the spoofing of the conn_rec associated with
+ * the incoming request if the proxy is about to add information to the
+ * request's X-Forwarded-For header. Without this the wrong IP (the
+ * spoof one) is added to the X-Forwarded-For header.
+ */
+static int mef_before_proxy_http(request_rec *r, 
+#if AP_SERVER_MINORVERSION_NUMBER >= 2
+                                 proxy_worker *worker,
+#endif
+                                 proxy_server_conf *pconf,
+                                 char *url, const char *proxyname, 
+                                 apr_port_t proxyport)
+{
+    MEFsave_rec *saved;
+    /*
+     * If our post-read-request handler did something we may have to too 
+     */
+    if ((saved = (MEFsave_rec *)ap_get_module_config(r->request_config, 
+                                         &extract_forwarded_module)) != NULL)
+    {
+        /*
+         * If proxy_http is going to add X-Forwarded-For info then we have
+         * have to undo the changes we made earlier so proxy_http can get 
+         * it right
+         */
+        if (PROXYREQ_REVERSE == r->proxyreq) 
+        {
+            extract_forwarded_undo_spoof(saved,  r, "before proxy http");
+        }
+    }
+    return DECLINED;
+}
+
+/*
+ * mef_logging() is used to redo the spoofing of the conn_rec associated
+ * with the incoming request if was undone.
+ * Redoing the spoof is to ensure that the spoof IP is used for logging 
+ * information about the request
+ */
+static int mef_logging(request_rec *r)
+{
+    MEFsave_rec *saved;
+    /*
+     * If our post-read-request handler did something we may have to too 
+     */
+    if ((saved = (MEFsave_rec *)ap_get_module_config(r->request_config, 
+                                         &extract_forwarded_module)) != NULL)
+    {
+        /*
+         * If we undid the spoof, probably because proxy_http was adding 
+         * X-Forwarded-For info, then we want to redo the changes we
+         * undid so the spook IP is logged
+         */
+        if (saved->conn_rec_mod_state == CONN_REC_RESTORED) 
+        {
+            redo_spoof(saved, r, "logging");
+        }
+    }
+    return DECLINED;
+}
+
+/*--------------------------------------------------------------------------*/
+/*                                                                          */
+/* Data structures pulling all the mef module's bits together               */
+/*                                                                          */
+/*--------------------------------------------------------------------------*/
+/*
+ * mef module's functions attached to request processing hooks. 
+ */
+static void mef_register_hooks(apr_pool_t *p)
+{
+    /* 
+     * Only need to register the following handlers if proxy_http_module
+     * is going to be loaded
+     */
+    static const char *const mef_proxy_b4[] = { "proxy_http.c", NULL };
+    proxy_hook_scheme_handler(mef_before_proxy_http, NULL, mef_proxy_b4,
+                              APR_HOOK_FIRST);
+    ap_hook_log_transaction(mef_logging, NULL, NULL, APR_HOOK_FIRST);
+}
+
+/* 
+ * mef module's definition for configuration. 
+ */
+module AP_MODULE_DECLARE_DATA extract_forwarded_module =
+{
+    STANDARD20_MODULE_STUFF,
+    NULL,                       /* per-directory config creator */
+    NULL,                       /* dir config merger */
+    NULL,                       /* server config creator */
+    NULL,                       /* server config merger */
+    NULL,                       /* command table */
+    mef_register_hooks,         /* set up other request processing hooks */
+};
@
