Cloudflare - Version 1.3.13

Version Description

  • Clarified error messaging in the plugin further
  • Added cURL error detection to explain issues with server installed cert bundles
Download this release

Release Info

Developer furkan811
Plugin Icon 128x128 Cloudflare
Version 1.3.13
Comparing to
See all releases

Version 1.3.13

Files changed (3) hide show
  1. cloudflare.php +474 -0
  2. ip_in_range.php +214 -0
  3. readme.txt +154 -0
cloudflare.php ADDED
@@ -0,0 +1,474 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: CloudFlare
4
+ Plugin URI: http://www.cloudflare.com/wiki/CloudFlareWordPressPlugin
5
+ Description: CloudFlare integrates your blog with the CloudFlare platform.
6
+ Version: 1.3.13
7
+ Author: Ian Pye, Jerome Chen, James Greene, Simon Moore (CloudFlare Team)
8
+ License: GPLv2
9
+ */
10
+
11
+ /*
12
+ This program is free software; you can redistribute it and/or modify
13
+ it under the terms of the GNU General Public License as published by
14
+ the Free Software Foundation; version 2 of the License.
15
+
16
+ This program is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU General Public License for more details.
20
+
21
+ You should have received a copy of the GNU General Public License
22
+ along with this program; if not, write to the Free Software
23
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
+
25
+ Plugin adapted from the Akismet WP plugin.
26
+
27
+ */
28
+
29
+ define('CLOUDFLARE_VERSION', '1.3.13');
30
+ define('CLOUDFLARE_API_URL', 'https://www.cloudflare.com/api_json.html');
31
+
32
+ require_once("ip_in_range.php");
33
+
34
+ // Make sure we don't expose any info if called directly
35
+ if ( !function_exists( 'add_action' ) ) {
36
+ echo "Hi there! I'm just a plugin, not much I can do when called directly.";
37
+ exit;
38
+ }
39
+
40
+ function cloudflare_init() {
41
+ global $cf_api_host, $cf_api_port, $is_cf;
42
+
43
+ $cf_api_host = "ssl://www.cloudflare.com";
44
+ $cf_api_port = 443;
45
+
46
+ $is_cf = (isset($_SERVER["HTTP_CF_CONNECTING_IP"]))? TRUE: FALSE;
47
+
48
+ if (strpos($_SERVER["REMOTE_ADDR"], ":") === FALSE) {
49
+ $cf_ip_ranges = array("173.245.48.0/20","103.21.244.0/22","103.22.200.0/22","103.31.4.0/22","141.101.64.0/18","108.162.192.0/18","190.93.240.0/20","188.114.96.0/20","197.234.240.0/22","198.41.128.0/17","162.158.0.0/15","199.27.128.0/21");
50
+ // IPV4: Update the REMOTE_ADDR value if the current REMOTE_ADDR value is in the specified range.
51
+ foreach ($cf_ip_ranges as $range) {
52
+ if (ipv4_in_range($_SERVER["REMOTE_ADDR"], $range)) {
53
+ if ($_SERVER["HTTP_CF_CONNECTING_IP"]) {
54
+ $_SERVER["REMOTE_ADDR"] = $_SERVER["HTTP_CF_CONNECTING_IP"];
55
+ }
56
+ break;
57
+ }
58
+ }
59
+ }
60
+ else {
61
+ $cf_ip_ranges = array("2400:cb00::/32", "2606:4700::/32", "2803:f800::/32");
62
+ $ipv6 = get_ipv6_full($_SERVER["REMOTE_ADDR"]);
63
+ foreach ($cf_ip_ranges as $range) {
64
+ if (ipv6_in_range($ipv6, $range)) {
65
+ if ($_SERVER["HTTP_CF_CONNECTING_IP"]) {
66
+ $_SERVER["REMOTE_ADDR"] = $_SERVER["HTTP_CF_CONNECTING_IP"];
67
+ }
68
+ break;
69
+ }
70
+ }
71
+ }
72
+
73
+ // Let people know that the CF WP plugin is turned on.
74
+ if (!headers_sent()) {
75
+ header("X-CF-Powered-By: WP " . CLOUDFLARE_VERSION);
76
+ }
77
+ add_action('admin_menu', 'cloudflare_config_page');
78
+ cloudflare_admin_warnings();
79
+ }
80
+ add_action('init', 'cloudflare_init',1);
81
+
82
+ function cloudflare_admin_init() {
83
+
84
+ }
85
+
86
+ add_action('admin_init', 'cloudflare_admin_init');
87
+
88
+ function cloudflare_config_page() {
89
+ if ( function_exists('add_submenu_page') ) {
90
+ add_submenu_page('plugins.php', __('CloudFlare Configuration'), __('CloudFlare'), 'manage_options', 'cloudflare', 'cloudflare_conf');
91
+ }
92
+ }
93
+
94
+ function load_cloudflare_keys () {
95
+ global $cloudflare_api_key, $cloudflare_api_email;
96
+ if (!$cloudflare_api_key) {
97
+ $cloudflare_api_key = get_option('cloudflare_api_key');
98
+ }
99
+ if (!$cloudflare_api_email) {
100
+ $cloudflare_api_email = get_option('cloudflare_api_email');
101
+ }
102
+ }
103
+
104
+ function cloudflare_conf() {
105
+ if ( function_exists('current_user_can') && !current_user_can('manage_options') )
106
+ die(__('Cheatin&#8217; uh?'));
107
+ global $cloudflare_api_key, $cloudflare_api_email, $is_cf;
108
+ global $wpdb;
109
+
110
+ $messages = array(
111
+ 'ip_restore_on' => array('color' => '000', 'text' => __('Plugin Status: True visitor IP is being restored')),
112
+ 'comment_spam_on' => array('color' => '000', 'text' => __('Plugin Status: CloudFlare will be notified when you mark comments as spam')),
113
+ 'curl_not_installed' => array('color' => 'FFA824', 'text' => __('Plugin Status: cURL is not installed/enabled on your server. You will not be able to toggle <a href="https://support.cloudflare.com/entries/22280726-what-does-cloudflare-development-mode-mean" target="_blank">development mode</a> via this plugin. If you wish to do this, please contact your server administrator or hosting provider for assistance with installing cURL.')),
114
+ 'dev_mode_on' => array('color' => '2d2', 'text' => __('Development mode is On. Happy blogging!')),
115
+ 'dev_mode_off' => array('color' => 'aa0', 'text' => __('Development mode is Off. Happy blogging!')),
116
+ );
117
+
118
+ $ms = array();
119
+ $ms[] = 'ip_restore_on';
120
+ $ms[] = 'comment_spam_on';
121
+
122
+ // get raw domain - may include www.
123
+ $urlparts = parse_url(site_url());
124
+ $raw_domain = $urlparts["host"];
125
+
126
+ $curl_installed = function_exists('curl_init');
127
+
128
+ $domain = null;
129
+
130
+ if (!$curl_installed) $ms[] = 'curl_not_installed';
131
+
132
+ if ($curl_installed) {
133
+ // Attempt to get the matching host from CF
134
+ $domain = get_domain($cloudflare_api_key, $cloudflare_api_email, $raw_domain);
135
+
136
+ // If not found, default to pulling the domain via client side.
137
+ if (is_wp_error($domain)) {
138
+ $messages['get_domain_failed'] = array('color' => 'FFA824', 'text' => __('Unable to get domain via CloudFlare API - ' . $domain->get_error_message()));
139
+ $ms[] = 'get_domain_failed';
140
+ $domain = null;
141
+ }
142
+ else if ($domain == null) {
143
+ $messages['domain_not_found'] = array('color' => 'FFA824', 'text' => __('Could not find your domain via CloudFlare API, assuming your CloudFlare domain is: ' . $raw_domain));
144
+ $ms[] = 'domain_not_found';
145
+ }
146
+ }
147
+
148
+ if ($domain == null) {
149
+ $domain = $raw_domain;
150
+ }
151
+
152
+ define ("THIS_DOMAIN", $domain);
153
+
154
+ $db_results = array();
155
+
156
+ if ( isset($_POST['submit'])
157
+ && check_admin_referer('cloudflare-db-api','cloudflare-db-api-nonce') ) {
158
+
159
+ if ( function_exists('current_user_can') && !current_user_can('manage_options') ) {
160
+ die(__('Cheatin&#8217; uh?'));
161
+ }
162
+
163
+ $key = $_POST['key'];
164
+ $email = $_POST['email'];
165
+ $dev_mode = esc_sql($_POST["dev_mode"]);
166
+
167
+ if ( empty($key) ) {
168
+ $key_status = 'empty';
169
+ $key_message = 'Your key has been cleared.';
170
+ delete_option('cloudflare_api_key');
171
+ } else {
172
+ $key_message = 'Your key has been verified.';
173
+ update_option('cloudflare_api_key', esc_sql($key));
174
+ update_option('cloudflare_api_key_set_once', "TRUE");
175
+ }
176
+
177
+ if ( empty($email) || !is_email($email) ) {
178
+ $email_status = 'empty';
179
+ $email_message = 'Your email has been cleared.';
180
+ delete_option('cloudflare_api_email');
181
+ } else {
182
+ $email_message = 'Your email has been verified.';
183
+ update_option('cloudflare_api_email', esc_sql($email));
184
+ update_option('cloudflare_api_email_set_once', "TRUE");
185
+ }
186
+
187
+ if ($curl_installed) {
188
+ if ($key != "" && $email != "") {
189
+
190
+ $result = set_dev_mode(esc_sql($key), esc_sql($email), THIS_DOMAIN, $dev_mode);
191
+
192
+ if (is_wp_error($result)) {
193
+ error_log($result->get_error_message());
194
+ $messages['set_dev_mode_failed'] = array('color' => 'FFA824', 'text' => __('Unable to set dev_mode - ' . $result->get_error_message() . ' - try logging into cloudflare.com to set development mode'));
195
+ $ms[] = 'set_dev_mode_failed';
196
+ }
197
+ else {
198
+ if ($dev_mode && $result->result == 'success') {
199
+ $ms[] = 'dev_mode_on';
200
+ }
201
+ else if (!$dev_mode && $result->result == 'success') {
202
+ $ms[] = 'dev_mode_off';
203
+ }
204
+ }
205
+
206
+
207
+ }
208
+ }
209
+ }
210
+ ?>
211
+ <div class="wrap">
212
+
213
+ <?php if ($is_cf) { ?>
214
+ <h3>You are currently using CloudFlare!</h3>
215
+ <?php } ?>
216
+
217
+ <?php if ( !empty($_POST['submit'] )) { ?>
218
+ <div id="message" class="updated fade"><p><strong><?php _e('Options saved.') ?></strong></p></div>
219
+ <?php } ?>
220
+ <?php if ($ms) { foreach ( $ms as $m ) { ?>
221
+ <div id="message" class="updated fade"><p style="padding: .5em; color: #<?php echo $messages[$m]['color']; ?>; font-weight: bold;"><?php echo $messages[$m]['text']; ?></p></div>
222
+ <?php } } ?>
223
+
224
+ <h4><?php _e('CLOUDFLARE WORDPRESS PLUGIN:'); ?></h4>
225
+ <?php // <div class="narrow"> ?>
226
+
227
+ CloudFlare has developed a plugin for WordPress. By using the CloudFlare WordPress Plugin, you receive:
228
+ <ol>
229
+ <li>Correct IP Address information for comments posted to your site</li>
230
+ <li>Better protection as spammers from your WordPress blog get reported to CloudFlare</li>
231
+ <li>If cURL is installed, you can enter your CloudFlare API details so you can toggle <a href="https://support.cloudflare.com/entries/22280726-what-does-cloudflare-development-mode-mean" target="_blank">Development mode</a> on/off using the form below</li>
232
+ </ol>
233
+
234
+ <h4>VERSION COMPATIBILITY:</h4>
235
+
236
+ The plugin is compatible with WordPress version 2.8.6 and later. The plugin will not install unless you have a compatible platform.
237
+
238
+ <h4>THINGS YOU NEED TO KNOW:</h4>
239
+
240
+ <ol>
241
+ <li>The main purpose of this plugin is to ensure you have no change to your originating IPs when using CloudFlare. Since CloudFlare acts a reverse proxy, connecting IPs now come from CloudFlare's range. This plugin will ensure you can continue to see the originating IP. Once you install the plugin, the IP benefit will be activated.</li>
242
+
243
+ <li>Every time you click the 'spam' button on your blog, this threat information is sent to CloudFlare to ensure you are constantly getting the best site protection.</li>
244
+
245
+ <li>We recommend that any user on CloudFlare with WordPress use this plugin. </li>
246
+
247
+ <li>NOTE: This plugin is complementary to Akismet and W3 Total Cache. We recommend that you continue to use those services.</li>
248
+
249
+ </ol>
250
+
251
+ <h4>MORE INFORMATION ON CLOUDFLARE:</h4>
252
+
253
+ CloudFlare is a service that makes websites load faster and protects sites from online spammers and hackers. Any website with a root domain (ie www.mydomain.com) can use CloudFlare. On average, it takes less than 5 minutes to sign up. You can learn more here: <a href="http://www.cloudflare.com/">CloudFlare.com</a>.
254
+
255
+ <?php
256
+ if ($curl_installed) {
257
+ $dev_mode = get_dev_mode_status($cloudflare_api_key, $cloudflare_api_email, THIS_DOMAIN);
258
+ if (is_wp_error($dev_mode)) {
259
+ $messages['get_dev_mode_failed'] = array('color' => 'aa0', 'text' => __('Unable to get dev_mode status - ' . $dev_mode->get_error_message()));
260
+ $ms[] = 'get_dev_mode_failed';
261
+ }
262
+ }
263
+ ?>
264
+
265
+ <hr />
266
+
267
+ <form action="" method="post" id="cloudflare-conf">
268
+ <?php wp_nonce_field('cloudflare-db-api','cloudflare-db-api-nonce'); ?>
269
+ <?php if (get_option('cloudflare_api_key') && get_option('cloudflare_api_email')) { ?>
270
+ <?php } else { ?>
271
+ <p><?php printf(__('Input your API key from your CloudFlare Accounts Settings page here. To find your API key, log in to <a href="%1$s">CloudFlare</a> and go to \'Account\'.'), 'https://www.cloudflare.com/my-account.html'); ?></p>
272
+ <?php } ?>
273
+ <h3><label for="key"><?php _e('CloudFlare API Key'); ?></label></h3>
274
+ <p>
275
+ <input id="key" name="key" type="text" size="50" maxlength="48" value="<?php echo get_option('cloudflare_api_key'); ?>" style="font-family: 'Courier New', Courier, mono; font-size: 1.5em;" /> (<?php _e('<a href="https://www.cloudflare.com/my-account.html">Get this?</a>'); ?>)
276
+ </p>
277
+ <?php if (isset($key_message)) echo sprintf('<p>%s</p>', $key_message); ?>
278
+
279
+ <h3><label for="email"><?php _e('CloudFlare API Email'); ?></label></h3>
280
+ <p>
281
+ <input id="email" name="email" type="text" size="50" maxlength="48" value="<?php echo get_option('cloudflare_api_email'); ?>" style="font-family: 'Courier New', Courier, mono; font-size: 1.5em;" /> (<?php _e('<a href="https://www.cloudflare.com/my-account.html">Get this?</a>'); ?>)
282
+ </p>
283
+ <?php if (isset($key_message)) echo sprintf('<p>%s</p>', $key_message); ?>
284
+
285
+ <h3><label for="dev_mode"><?php _e('Development Mode'); ?></label> <span style="font-size:9pt;">(<a href="https://support.cloudflare.com/entries/22280726-what-does-cloudflare-development-mode-mean" " target="_blank">What is this?</a>)</span></h3>
286
+
287
+ <?php if ($curl_installed) { ?>
288
+ <div style="font-family: 'Courier New', Courier, mono; font-size: 1.5em;">
289
+ <input type="radio" name="dev_mode" value="0" <?php if ($dev_mode == "off") echo "checked"; ?>> Off
290
+ <input type="radio" name="dev_mode" value="1" <?php if ($dev_mode == "on") echo "checked"; ?>> On
291
+ </div>
292
+ <?php } ?>
293
+ </p>
294
+ <p class="submit"><input type="submit" name="submit" value="<?php _e('Update options &raquo;'); ?>" /></p>
295
+ </form>
296
+
297
+ <?php // </div> ?>
298
+ </div>
299
+ <?php
300
+ }
301
+
302
+ function cloudflare_admin_warnings() {
303
+
304
+ global $cloudflare_api_key, $cloudflare_api_email;
305
+ load_cloudflare_keys();
306
+ }
307
+
308
+ // Now actually allow CF to see when a comment is approved/not-approved.
309
+ function cloudflare_set_comment_status($id, $status) {
310
+ global $cf_api_host, $cf_api_port, $cloudflare_api_key, $cloudflare_api_email;
311
+ if (!$cf_api_host || !$cf_api_port) {
312
+ return;
313
+ }
314
+ load_cloudflare_keys();
315
+ if (!$cloudflare_api_key || !$cloudflare_api_email) {
316
+ return;
317
+ }
318
+
319
+ // ajax/external-event.html?email=ian@cloudflare.com&t=94606855d7e42adf3b9e2fd004c7660b941b8e55aa42d&evnt_v={%22dd%22:%22d%22}&evnt_t=WP_SPAM
320
+ $comment = get_comment($id);
321
+ $value = array("a" => $comment->comment_author,
322
+ "am" => $comment->comment_author_email,
323
+ "ip" => $comment->comment_author_IP,
324
+ "con" => substr($comment->comment_content, 0, 100));
325
+ $url = "/ajax/external-event.html?evnt_v=" . urlencode(json_encode($value)) . "&u=$cloudflare_api_email&tkn=$cloudflare_api_key&evnt_t=";
326
+
327
+ // If spam, send this info over to CloudFlare.
328
+ if ($status == "spam") {
329
+ $url .= "WP_SPAM";
330
+ $fp = @fsockopen($cf_api_host, $cf_api_port, $errno, $errstr, 30);
331
+ if ($fp) {
332
+ $out = "GET $url HTTP/1.1\r\n";
333
+ $out .= "Host: www.cloudflare.com\r\n";
334
+ $out .= "Connection: Close\r\n\r\n";
335
+ fwrite($fp, $out);
336
+ $res = "";
337
+ while (!feof($fp)) {
338
+ $res .= fgets($fp, 128);
339
+ }
340
+ fclose($fp);
341
+ }
342
+ }
343
+ }
344
+
345
+ add_action('wp_set_comment_status', 'cloudflare_set_comment_status', 1, 2);
346
+
347
+ function get_dev_mode_status($token, $email, $zone) {
348
+
349
+ $fields = array(
350
+ 'a'=>"zone_load",
351
+ 'tkn'=>$token,
352
+ 'email'=>$email,
353
+ 'z'=>$zone
354
+ );
355
+
356
+ $result = cloudflare_curl(CLOUDFLARE_API_URL, $fields, true);
357
+
358
+ if (is_wp_error($result)) {
359
+ error_log($result->get_error_message());
360
+ return $result;
361
+ }
362
+
363
+ if ($result->response->zone->obj->zone_status_class == "status-dev-mode") {
364
+ return "on";
365
+ }
366
+
367
+ return "off";
368
+ }
369
+
370
+ function set_dev_mode($token, $email, $zone, $value) {
371
+
372
+ $fields = array(
373
+ 'a'=>"devmode",
374
+ 'tkn'=>$token,
375
+ 'email'=>$email,
376
+ 'z'=>$zone,
377
+ 'v'=>$value
378
+ );
379
+
380
+ $result = cloudflare_curl(CLOUDFLARE_API_URL, $fields, true);
381
+
382
+ if (is_wp_error($result)) {
383
+ error_log($result->get_error_message());
384
+ return $result;
385
+ }
386
+
387
+ return $result;
388
+ }
389
+
390
+ function get_domain($token, $email, $raw_domain) {
391
+
392
+ $fields = array(
393
+ 'a'=>"zone_load_multi",
394
+ 'tkn'=>$token,
395
+ 'email'=>$email
396
+ );
397
+
398
+ $result = cloudflare_curl(CLOUDFLARE_API_URL, $fields, true);
399
+
400
+ if (is_wp_error($result)) {
401
+ error_log($result->get_error_message());
402
+ return $result;
403
+ }
404
+
405
+ $zone_count = $result->response->zones->count;
406
+ if ($zone_count > 0) {
407
+ for ($i = 0; $i < $zone_count; $i++) {
408
+ $zone_name = $result->response->zones->objs[$i]->zone_name;
409
+ if (strpos($raw_domain, $zone_name) !== FALSE){
410
+ return $zone_name;
411
+ }
412
+ }
413
+ }
414
+
415
+ return null;
416
+ }
417
+
418
+ /**
419
+ * @param $url string the URL to curl
420
+ * @param $fields array an associative array of arguments for POSTing
421
+ * @param $json boolean attempt to decode response as JSON
422
+ *
423
+ * @returns WP_ERROR|string|object in the case of an error, otherwise a $result string or JSON object
424
+ */
425
+ function cloudflare_curl($url, $fields = array(), $json = true) {
426
+
427
+ $ch = curl_init();
428
+
429
+ curl_setopt($ch,CURLOPT_URL,$url);
430
+
431
+ if (!empty($fields)) {
432
+
433
+ $fields_string = '';
434
+
435
+ foreach($fields as $key=>$value) {
436
+ $fields_string .= $key.'='.$value.'&';
437
+ }
438
+ rtrim($fields_string,'&');
439
+
440
+ curl_setopt($ch,CURLOPT_POST,count($fields));
441
+ curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string);
442
+ }
443
+
444
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
445
+
446
+ $result = curl_exec($ch);
447
+
448
+ if ($result == false) {
449
+ $curl_error = curl_error($ch);
450
+ $curl_error_number = curl_errno($ch);
451
+
452
+ // Attempt to detect a possible invalid cert bundle on the server - CURLE_SSL_CACERT (60)
453
+ // Ref: http://curl.haxx.se/libcurl/c/libcurl-errors.html
454
+ if ($curl_error_number == 60) {
455
+ return new WP_Error('curl', sprintf('cURL returned an SSL related error when contacting the CloudFlare API using HTTPS. It is possible that your server\'s CA cert bundle is out of date. You should contact your server administrator or hosting provider and ask them to check that you have the latest CA Cert bundle installed. cURL Error: %d - %s', $curl_error_number, $curl_error), $curl_error_number);
456
+ }
457
+ else {
458
+ return new WP_Error('curl', sprintf('cURL request failed: %d - %s', $curl_error_number, $curl_error), $curl_error_number);
459
+ }
460
+ }
461
+
462
+ if ($json == true) {
463
+ $result = json_decode($result);
464
+ // not a perfect test, but better than nothing perhaps
465
+ if ($result == null) {
466
+ return new WP_Error('json_decode', sprintf('Unable to decode JSON response'), $result);
467
+ }
468
+ }
469
+
470
+ curl_close($ch);
471
+
472
+ return $result;
473
+ }
474
+ ?>
ip_in_range.php ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * ip_in_range.php - Function to determine if an IP is located in a
5
+ * specific range as specified via several alternative
6
+ * formats.
7
+ *
8
+ * Network ranges can be specified as:
9
+ * 1. Wildcard format: 1.2.3.*
10
+ * 2. CIDR format: 1.2.3/24 OR 1.2.3.4/255.255.255.0
11
+ * 3. Start-End IP format: 1.2.3.0-1.2.3.255
12
+ *
13
+ * Return value BOOLEAN : ip_in_range($ip, $range);
14
+ *
15
+ * Copyright 2008: Paul Gregg <pgregg@pgregg.com>
16
+ * 10 January 2008
17
+ * Version: 1.2
18
+ *
19
+ * Source website: http://www.pgregg.com/projects/php/ip_in_range/
20
+ * Version 1.2
21
+ *
22
+ * This software is Donationware - if you feel you have benefited from
23
+ * the use of this tool then please consider a donation. The value of
24
+ * which is entirely left up to your discretion.
25
+ * http://www.pgregg.com/donate/
26
+ *
27
+ * Please do not remove this header, or source attibution from this file.
28
+ */
29
+
30
+ /*
31
+ * Modified by James Greene <james@cloudflare.com> to include IPV6 support
32
+ * (original version only supported IPV4).
33
+ * 21 May 2012
34
+ */
35
+
36
+
37
+ // decbin32
38
+ // In order to simplify working with IP addresses (in binary) and their
39
+ // netmasks, it is easier to ensure that the binary strings are padded
40
+ // with zeros out to 32 characters - IP addresses are 32 bit numbers
41
+ function decbin32 ($dec) {
42
+ return str_pad(decbin($dec), 32, '0', STR_PAD_LEFT);
43
+ }
44
+
45
+ // ipv4_in_range
46
+ // This function takes 2 arguments, an IP address and a "range" in several
47
+ // different formats.
48
+ // Network ranges can be specified as:
49
+ // 1. Wildcard format: 1.2.3.*
50
+ // 2. CIDR format: 1.2.3/24 OR 1.2.3.4/255.255.255.0
51
+ // 3. Start-End IP format: 1.2.3.0-1.2.3.255
52
+ // The function will return true if the supplied IP is within the range.
53
+ // Note little validation is done on the range inputs - it expects you to
54
+ // use one of the above 3 formats.
55
+ function ipv4_in_range($ip, $range) {
56
+ if (strpos($range, '/') !== false) {
57
+ // $range is in IP/NETMASK format
58
+ list($range, $netmask) = explode('/', $range, 2);
59
+ if (strpos($netmask, '.') !== false) {
60
+ // $netmask is a 255.255.0.0 format
61
+ $netmask = str_replace('*', '0', $netmask);
62
+ $netmask_dec = ip2long($netmask);
63
+ return ( (ip2long($ip) & $netmask_dec) == (ip2long($range) & $netmask_dec) );
64
+ } else {
65
+ // $netmask is a CIDR size block
66
+ // fix the range argument
67
+ $x = explode('.', $range);
68
+ while(count($x)<4) $x[] = '0';
69
+ list($a,$b,$c,$d) = $x;
70
+ $range = sprintf("%u.%u.%u.%u", empty($a)?'0':$a, empty($b)?'0':$b,empty($c)?'0':$c,empty($d)?'0':$d);
71
+ $range_dec = ip2long($range);
72
+ $ip_dec = ip2long($ip);
73
+
74
+ # Strategy 1 - Create the netmask with 'netmask' 1s and then fill it to 32 with 0s
75
+ #$netmask_dec = bindec(str_pad('', $netmask, '1') . str_pad('', 32-$netmask, '0'));
76
+
77
+ # Strategy 2 - Use math to create it
78
+ $wildcard_dec = pow(2, (32-$netmask)) - 1;
79
+ $netmask_dec = ~ $wildcard_dec;
80
+
81
+ return (($ip_dec & $netmask_dec) == ($range_dec & $netmask_dec));
82
+ }
83
+ } else {
84
+ // range might be 255.255.*.* or 1.2.3.0-1.2.3.255
85
+ if (strpos($range, '*') !==false) { // a.b.*.* format
86
+ // Just convert to A-B format by setting * to 0 for A and 255 for B
87
+ $lower = str_replace('*', '0', $range);
88
+ $upper = str_replace('*', '255', $range);
89
+ $range = "$lower-$upper";
90
+ }
91
+
92
+ if (strpos($range, '-')!==false) { // A-B format
93
+ list($lower, $upper) = explode('-', $range, 2);
94
+ $lower_dec = (float)sprintf("%u",ip2long($lower));
95
+ $upper_dec = (float)sprintf("%u",ip2long($upper));
96
+ $ip_dec = (float)sprintf("%u",ip2long($ip));
97
+ return ( ($ip_dec>=$lower_dec) && ($ip_dec<=$upper_dec) );
98
+ }
99
+ return false;
100
+ }
101
+ }
102
+
103
+ function ip2long6($ip) {
104
+ if (substr_count($ip, '::')) {
105
+ $ip = str_replace('::', str_repeat(':0000', 8 - substr_count($ip, ':')) . ':', $ip);
106
+ }
107
+
108
+ $ip = explode(':', $ip);
109
+ $r_ip = '';
110
+ foreach ($ip as $v) {
111
+ $r_ip .= str_pad(base_convert($v, 16, 2), 16, 0, STR_PAD_LEFT);
112
+ }
113
+
114
+ return base_convert($r_ip, 2, 10);
115
+ }
116
+
117
+ // Get the ipv6 full format and return it as a decimal value.
118
+ function get_ipv6_full($ip)
119
+ {
120
+ $pieces = explode ("/", $ip, 2);
121
+ $left_piece = $pieces[0];
122
+ $right_piece = $pieces[1];
123
+
124
+ // Extract out the main IP pieces
125
+ $ip_pieces = explode("::", $left_piece, 2);
126
+ $main_ip_piece = $ip_pieces[0];
127
+ $last_ip_piece = $ip_pieces[1];
128
+
129
+ // Pad out the shorthand entries.
130
+ $main_ip_pieces = explode(":", $main_ip_piece);
131
+ foreach($main_ip_pieces as $key=>$val) {
132
+ $main_ip_pieces[$key] = str_pad($main_ip_pieces[$key], 4, "0", STR_PAD_LEFT);
133
+ }
134
+
135
+ // Check to see if the last IP block (part after ::) is set
136
+ $last_piece = "";
137
+ $size = count($main_ip_pieces);
138
+ if (trim($last_ip_piece) != "") {
139
+ $last_piece = str_pad($last_ip_piece, 4, "0", STR_PAD_LEFT);
140
+
141
+ // Build the full form of the IPV6 address considering the last IP block set
142
+ for ($i = $size; $i < 7; $i++) {
143
+ $main_ip_pieces[$i] = "0000";
144
+ }
145
+ $main_ip_pieces[7] = $last_piece;
146
+ }
147
+ else {
148
+ // Build the full form of the IPV6 address
149
+ for ($i = $size; $i < 8; $i++) {
150
+ $main_ip_pieces[$i] = "0000";
151
+ }
152
+ }
153
+
154
+ // Rebuild the final long form IPV6 address
155
+ $final_ip = implode(":", $main_ip_pieces);
156
+
157
+ return ip2long6($final_ip);
158
+ }
159
+
160
+
161
+ // Determine whether the IPV6 address is within range.
162
+ // $ip is the IPV6 address in decimal format to check if its within the IP range created by the cloudflare IPV6 address, $range_ip.
163
+ // $ip and $range_ip are converted to full IPV6 format.
164
+ // Returns true if the IPV6 address, $ip, is within the range from $range_ip. False otherwise.
165
+ function ipv6_in_range($ip, $range_ip)
166
+ {
167
+ $pieces = explode ("/", $range_ip, 2);
168
+ $left_piece = $pieces[0];
169
+ $right_piece = $pieces[1];
170
+
171
+ // Extract out the main IP pieces
172
+ $ip_pieces = explode("::", $left_piece, 2);
173
+ $main_ip_piece = $ip_pieces[0];
174
+ $last_ip_piece = $ip_pieces[1];
175
+
176
+ // Pad out the shorthand entries.
177
+ $main_ip_pieces = explode(":", $main_ip_piece);
178
+ foreach($main_ip_pieces as $key=>$val) {
179
+ $main_ip_pieces[$key] = str_pad($main_ip_pieces[$key], 4, "0", STR_PAD_LEFT);
180
+ }
181
+
182
+ // Create the first and last pieces that will denote the IPV6 range.
183
+ $first = $main_ip_pieces;
184
+ $last = $main_ip_pieces;
185
+
186
+ // Check to see if the last IP block (part after ::) is set
187
+ $last_piece = "";
188
+ $size = count($main_ip_pieces);
189
+ if (trim($last_ip_piece) != "") {
190
+ $last_piece = str_pad($last_ip_piece, 4, "0", STR_PAD_LEFT);
191
+
192
+ // Build the full form of the IPV6 address considering the last IP block set
193
+ for ($i = $size; $i < 7; $i++) {
194
+ $first[$i] = "0000";
195
+ $last[$i] = "ffff";
196
+ }
197
+ $main_ip_pieces[7] = $last_piece;
198
+ }
199
+ else {
200
+ // Build the full form of the IPV6 address
201
+ for ($i = $size; $i < 8; $i++) {
202
+ $first[$i] = "0000";
203
+ $last[$i] = "ffff";
204
+ }
205
+ }
206
+
207
+ // Rebuild the final long form IPV6 address
208
+ $first = ip2long6(implode(":", $first));
209
+ $last = ip2long6(implode(":", $last));
210
+ $in_range = ($ip >= $first && $ip <= $last);
211
+
212
+ return $in_range;
213
+ }
214
+ ?>
readme.txt ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === CloudFlare ===
2
+ Contributors: i3149, jchen329, jamescf, simon-says
3
+ Tags: cloudflare, comments, spam, cdn, free, website, performance, speed
4
+ Requires at least: 2.8
5
+ Tested up to: 3.8
6
+ Stable tag: 1.3.13
7
+ License: GPLv2
8
+
9
+ The CloudFlare WordPress Plugin ensures your WordPress blog is running optimally on the CloudFlare platform.
10
+
11
+ == Description ==
12
+
13
+ CloudFlare has developed a plugin for WordPress. By using the CloudFlare WordPress Plugin, you receive:
14
+
15
+ * Correct IP Address information for comments posted to your site
16
+
17
+ * Better protection as spammers from your WordPress blog get reported to CloudFlare
18
+
19
+ THINGS YOU NEED TO KNOW:
20
+
21
+ * The main purpose of this plugin is to ensure you have no change to your originating IPs when using CloudFlare. Since CloudFlare acts a reverse proxy, connecting IPs now come from CloudFlare's range. This plugin will ensure you can continue to see the originating IP.
22
+
23
+ * Every time you click the 'spam' button on your blog, this threat information is sent to CloudFlare to ensure you are constantly getting the best site protection.
24
+
25
+ * We recommend that any user on WordPress and CloudFlare should use this plugin.
26
+
27
+ MORE INFORMATION ON CLOUDFLARE:
28
+
29
+ CloudFlare is a service that makes websites load faster and protects sites from online spammers and hackers. Any website with a root domain (ie www.mydomain.com) can use CloudFlare. On average, it takes less than 5 minutes to sign up. You can learn more here: [CloudFlare.com](https://www.cloudflare.com/overview.html).
30
+
31
+ == Installation ==
32
+
33
+ Upload the CloudFlare plugin to your blog, Activate it, and you're done!
34
+
35
+ You will also want to sign up your blog with CloudFlare.com
36
+
37
+ [Read more](http://blog.cloudflare.com/introducing-the-cloudflare-wordpress-plugin) on why we created this plugin.
38
+
39
+ == Changelog ==
40
+
41
+ = 1.3.13 =
42
+
43
+ * Clarified error messaging in the plugin further
44
+ * Added cURL error detection to explain issues with server installed cert bundles
45
+
46
+ = 1.3.12 =
47
+
48
+ * Removed use of php short-code in a couple of places
49
+ * Added some cURL / json_decode error handling to output to the screen any failures
50
+ * Reformatted error / notice display slightly
51
+
52
+ = 1.3.11 =
53
+
54
+ * Adjusted a line syntax to account for differing PHP configurations.
55
+
56
+ = 1.3.10 =
57
+
58
+ * Added IP ranges.
59
+
60
+ = 1.3.9 =
61
+ * Made adjustment to syntax surrounding cURL detection for PHP installations that do not have short_open_tag enabled.
62
+
63
+ = 1.3.8 =
64
+ * Fixed issue with invalid header.
65
+ * Updated IP ranges
66
+ * Fixed support link
67
+
68
+ = 1.3.7 =
69
+ * Remove Database Optimizer related text.
70
+
71
+ = 1.3.6 =
72
+ * Remove Database Optimizer.
73
+
74
+ = 1.3.5 =
75
+ * Disable Development Mode option if cURL not installed. Will Use JSONP in future release to allow domains without cURL to use Development Mode.
76
+
77
+ = 1.3.4 =
78
+ * Add in IPV6 support and Development Mode option to wordpress plugin settings page. Remove cached IP range text file.
79
+
80
+ = 1.3.3 =
81
+ * Bump stable version number.
82
+
83
+ = 1.3.2.Beta =
84
+ * BETA RELEASE: IPv6 support - Pull the IPv6 range from https://www.cloudflare.com/ips-v6. Added Development Mode option to wordpress plugin settings page.
85
+
86
+ = 1.2.4 =
87
+ * Pull the IP range from https://www.cloudflare.com/ips-v4. Modified to keep all files within cloudflare plugin directory.
88
+
89
+ = 1.2.3 =
90
+ * Updated with new IP range
91
+
92
+ = 1.2.2 =
93
+ * Restricted database optimization to administrators
94
+
95
+ = 1.2.1 =
96
+ * Increased load priority to avoid conflicts with other plugins
97
+
98
+ = 1.2.0 =
99
+
100
+ * WP 3.3 compatibility.
101
+
102
+ = 1.1.9 =
103
+
104
+ * Includes latest CloudFlare IP allocation -- 108.162.192.0/18.
105
+
106
+ = 1.1.8 =
107
+
108
+ * WP 3.2 compatibility.
109
+
110
+ = 1.1.7 =
111
+
112
+ * Implements several security updates.
113
+
114
+ = 1.1.6 =
115
+
116
+ * Includes latest CloudFlare IP allocation -- 141.101.64.0/18.
117
+
118
+ = 1.1.5 =
119
+
120
+ * Includes latest CloudFlare IP allocation -- 103.22.200.0/22.
121
+
122
+ = 1.1.4 =
123
+
124
+ * Updated messaging.
125
+
126
+ = 1.1.3 =
127
+
128
+ * Better permission checking for DB optimizer.
129
+ * Added CloudFlare's latest /20 to the list of CloudFlare IP ranges.
130
+
131
+ = 1.1.2 =
132
+
133
+ * Fixed several broken help links.
134
+ * Fixed confusing error message.
135
+
136
+ = 1.1.1 =
137
+
138
+ * Fix for Admin menus which are breaking when page variable contains '-'.
139
+
140
+ = 1.1.0 =
141
+
142
+ * Added a box to input CloudFlare API credentials.
143
+ * Added a call to CloudFlare's report spam API when a comment is marked as spam.
144
+
145
+ = 1.0.1 =
146
+
147
+ * Fix to check that it is OK to add a header before adding one.
148
+
149
+ = 1.0.0 =
150
+
151
+ * Initial feature set
152
+ * Set RemoteIP header correctly.
153
+ * On comment spam, send the offending IP to CloudFlare.
154
+ * Clean up DB on load.