diff --git a/README.md b/README.md index cc5d0de..61a1290 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,23 @@ # mod_cloudflare for Apache # Copyright CloudFlare Inc. 2016 +Modded by p0358 + +## FORK INFO ## + +This fork adds `CLOUDFLARE_CONNECTION` env variable set to "true" if connection originated from one of module's trusted proxy IPs. It is very useful since you cannot add `DenyAllButCloudflare` directive everywhere, but instead you can now use `Require env CLOUDFLARE_CONNECTION` or `Require expr "-T env('CLOUDFLARE_CONNECTION')"` (the latter example provided if you want to mix it with other expressions, you could also consider the first one inside `RequireAll` block instead). + +To use it (replacing the original mode if you already use it), simply clone it and use install instructions from below. Or on Ubuntu/Debian you can just execute: + + git clone https://github.com/p0358/mod_cloudflare.git + cd mod_cloudflare + apt install apache2-dev + apxs2 -a -i -c mod_cloudflare.c + service apache2 restart + +CloudFlare is welcome to implement this in their official repo :) + + ## mod_cloudflare.c ## Based on mod_remoteip.c, this Apache extension will replace the remote_ip variable in user's logs with the correct remote IP sent from CloudFlare. The module only performs the IP substitution for requests originating from CloudFlare IPs by default. @@ -20,6 +37,7 @@ An alternative way to install is to use GNU autotools, which requires that autoc ### OS Support ### +- Debian/Ubuntu - Supported - CentOS - Supported - CloudLinux - Not Supported diff --git a/mod_cloudflare.c b/mod_cloudflare.c index 6631291..e9b2140 100644 --- a/mod_cloudflare.c +++ b/mod_cloudflare.c @@ -59,7 +59,6 @@ static const char* CF_DEFAULT_TRUSTED_PROXY[] = { "198.41.128.0/17", /* IPv6 Address Ranges */ "2400:cb00::/32", - "2405:8100::/32", "2405:b500::/32", "2606:4700::/32", "2803:f800::/32", @@ -282,11 +281,12 @@ static int cloudflare_modify_connection(request_rec *r) const char *cf_visitor_header = NULL; apr_pool_userdata_get((void*)&conn, "mod_cloudflare-conn", c->pool); + + apr_table_t *e = r->subprocess_env; cf_visitor_header = apr_table_get(r->headers_in, "CF-Visitor"); if (cf_visitor_header != NULL) { if ((remote) && (strstr(cf_visitor_header, "https") != NULL)) { - apr_table_t *e = r->subprocess_env; apr_table_addn(e, "HTTPS", "on"); } } @@ -371,6 +371,8 @@ static int cloudflare_modify_connection(request_rec *r) } else { break; } + } else { + apr_table_addn(e, "CLOUDFLARE_CONNECTION", "true"); // TODO: Check if this is indeed appended to each request, as I had some issues with random 403s (my Apache config denying if this env variable was not set) } } diff --git a/mod_cloudflare_conf_ip_update.php b/mod_cloudflare_conf_ip_update.php new file mode 100644 index 0000000..59c6e36 --- /dev/null +++ b/mod_cloudflare_conf_ip_update.php @@ -0,0 +1,60 @@ +/mod_cloudflare_conf_ip_update.php +// +// Created by p0358 + +$list = ''; +$arr = []; + +$ipv4 = file_get_contents('https://www.cloudflare.com/ips-v4'); +$ipv6 = file_get_contents('https://www.cloudflare.com/ips-v6'); +if (empty($ipv4) || empty($ipv6)) { + fwrite(STDERR, "Error: script could not download the latest IP ranges from Cloudflare\n"); + exit(1); +} + +$ipv4_arr = explode("\n", trim($ipv4)); +foreach ($ipv4_arr as &$line) { + // Source: https://www.regextester.com/98096 + if (preg_match('/^((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2])))$/', trim($line), $matches)) { + $arr[] = $matches[1]; + } +} + +$ipv6_arr = explode("\n", trim($ipv6)); +foreach ($ipv6_arr as &$line) { + // Source: https://www.regextester.com/93988 + if (preg_match('/^s*(((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?)$/', trim($line), $matches)) { + $arr[] = $matches[1]; + } +} + +if (empty($arr)) { + fwrite(STDERR, "Error: script got 0 results while trying to get the latest IP ranges from Cloudflare, terminating\n"); + exit(2); +} + +//$arr[] = ''; -- you can append your public server's IP(s) here too +$arr[] = '127.0.0.1'; +$arr[] = '::1'; + +$list = implode(' ', $arr); + +$datestring = date('Y-m-d H:i:s'); + +$content = << + CloudFlareRemoteIPHeader CF-Connecting-IP + CloudFlareRemoteIPTrustedProxy $list + #DenyAllButCloudFlare + +# Updated using mod_cloudflare_conf_ip_update.php by p0358 at $datestring +CONTENT; + +file_put_contents('/etc/apache2/mods-available/cloudflare.conf', $content);