Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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

Expand Down
6 changes: 4 additions & 2 deletions mod_cloudflare.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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");
}
}
Expand Down Expand Up @@ -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)
}
}

Expand Down
60 changes: 60 additions & 0 deletions mod_cloudflare_conf_ip_update.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

// A simple PHP script automatically updating Cloudflare IPs
// in mod_cloudflare's config file at /etc/apache2/mods-available/cloudflare.conf
// Works in Debian and will work in all OSs provided they have PHP and you optionally adjust config file location
// You can uncomment DenyAllButCloudFlare option in config content if you desire too
// Can be added to cron like so (remember about having correct permissions, so the executing user can write the config file):
// 0 0 * * * php /<path>/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 = <<<CONTENT
<IfModule mod_cloudflare.c>
CloudFlareRemoteIPHeader CF-Connecting-IP
CloudFlareRemoteIPTrustedProxy $list
#DenyAllButCloudFlare
</IfModule>
# Updated using mod_cloudflare_conf_ip_update.php by p0358 at $datestring
CONTENT;

file_put_contents('/etc/apache2/mods-available/cloudflare.conf', $content);