diff --git a/www/mod_extract_forwarded/Makefile b/www/mod_extract_forwarded/Makefile index f003d813011e..eea3b5147d5b 100644 --- a/www/mod_extract_forwarded/Makefile +++ b/www/mod_extract_forwarded/Makefile @@ -3,7 +3,7 @@ PORTNAME= mod_extract_forwarded PORTVERSION= 2.0.2 -PORTREVISION= 3 +PORTREVISION= 4 CATEGORIES= www MASTER_SITES= http://www.openinfo.co.uk/apache/ DISTNAME= extract_forwarded-${DISTVERSION} @@ -11,15 +11,31 @@ DISTNAME= extract_forwarded-${DISTVERSION} MAINTAINER= kuriyama@FreeBSD.org COMMENT= An Apache module that can make proxied requests appear with client IP +OPTIONS_DEFINE= YOSHFUJI +YOSHFUJI_DESC= yoshfuji patch (support IPv6 addr in config, etc) +#OPTIONS_DEFAULT= YOSHFUJI + USE_APACHE= 22 WRKSRC= ${WRKDIR}/extract_forwarded PORTDOCS= INSTALL README MAKE_JOBS_SAFE= yes -CONFLICTS= mod_extract_forwarded-1.* +PATCH_STRIP= -p1 AP_FAST_BUILD= yes AP_GENPLIST= yes +# Workaround for UNIQUENAME v.s. OptionsNG problem. +# http://lists.freebsd.org/pipermail/freebsd-ports/2012-June/075466.html +UNIQUENAME= ap22-${PORTNAME} + +.include + +.if ${PORT_OPTIONS:MYOSHFUJI} +EXTRA_PATCHES= ${FILESDIR}/extra-patch-yoshfuji +.else +EXTRA_PATCHES= ${FILESDIR}/extra-patch-mod_extract_forwarded.c +.endif + post-install: .if !defined(NOPORTDOCS) ${MKDIR} ${DOCSDIR}/ diff --git a/www/mod_extract_forwarded/files/patch-mod_extract_forwarded.c b/www/mod_extract_forwarded/files/extra-patch-mod_extract_forwarded.c similarity index 100% rename from www/mod_extract_forwarded/files/patch-mod_extract_forwarded.c rename to www/mod_extract_forwarded/files/extra-patch-mod_extract_forwarded.c diff --git a/www/mod_extract_forwarded/files/extra-patch-yoshfuji b/www/mod_extract_forwarded/files/extra-patch-yoshfuji new file mode 100644 index 000000000000..1bdaa57de998 --- /dev/null +++ b/www/mod_extract_forwarded/files/extra-patch-yoshfuji @@ -0,0 +1,918 @@ +# $FreeBSD$ +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 + #include + #include + +-/* +- * #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 @@ ++ ++ # 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 ++ ++ # 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. ++ +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 ++ * . ++ * ++ */ ++ ++#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 ++ * . ++ * ++ */ ++ ++#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 */ ++};