diff --git a/cloudflare/cloudflare.php b/cloudflare/cloudflare.php index 0ca9afa..29a55f9 100644 --- a/cloudflare/cloudflare.php +++ b/cloudflare/cloudflare.php @@ -3,8 +3,8 @@ Plugin Name: CloudFlare Plugin URI: http://www.cloudflare.com/wiki/CloudFlareWordPressPlugin Description: CloudFlare integrates your blog with the CloudFlare platform. -Version: 1.2.3 -Author: Ian Pye, Jerome Chen (CloudFlare Team) +Version: 1.3.6 +Author: Ian Pye, Jerome Chen, James Greene (CloudFlare Team) License: GPLv2 */ @@ -26,7 +26,7 @@ */ -define('CLOUDFLARE_VERSION', '1.2.1'); +define('CLOUDFLARE_VERSION', '1.3.6'); require_once("ip_in_range.php"); // Make sure we don't expose any info if called directly @@ -36,29 +36,44 @@ } function cloudflare_init() { - global $cf_api_host, $cf_api_port, $is_cf; + global $cf_api_host, $cf_api_port, $is_cf; $cf_api_host = "ssl://www.cloudflare.com"; $cf_api_port = 443; - $cf_ip_ranges = array("204.93.240.0/24", "204.93.177.0/24", "199.27.128.0/21", "173.245.48.0/20", "103.22.200.0/22", "141.101.64.0/18", "108.162.192.0/18","190.93.240.0/20"); + $is_cf = ($_SERVER["HTTP_CF_CONNECTING_IP"])? TRUE: FALSE; - // Update the REMOTE_ADDR value if the current REMOTE_ADDR value is in the specified range. - foreach ($cf_ip_ranges as $range) { - if (ip_in_range($_SERVER["REMOTE_ADDR"], $range)) { - if ($_SERVER["HTTP_CF_CONNECTING_IP"]) { - $_SERVER["REMOTE_ADDR"] = $_SERVER["HTTP_CF_CONNECTING_IP"]; + if (strpos($_SERVER["REMOTE_ADDR"], ":") === FALSE) { + $cf_ip_ranges = array("204.93.240.0/24", "204.93.177.0/24", "199.27.128.0/21", "173.245.48.0/20", "103.22.200.0/22", "141.101.64.0/18", "108.162.192.0/18","190.93.240.1/20"); + // IPV4: Update the REMOTE_ADDR value if the current REMOTE_ADDR value is in the specified range. + foreach ($cf_ip_ranges as $range) { + if (ipv4_in_range($_SERVER["REMOTE_ADDR"], $range)) { + if ($_SERVER["HTTP_CF_CONNECTING_IP"]) { + $_SERVER["REMOTE_ADDR"] = $_SERVER["HTTP_CF_CONNECTING_IP"]; + } + break; + } + } + } + else { + $cf_ip_ranges = array("2400:cb00::/32", "2606:4700::/32", "2803:f800::/32"); + $ipv6 = get_ipv6_full($_SERVER["REMOTE_ADDR"]); + foreach ($cf_ip_ranges as $range) { + if (ipv6_in_range($ipv6, $range)) { + if ($_SERVER["HTTP_CF_CONNECTING_IP"]) { + $_SERVER["REMOTE_ADDR"] = $_SERVER["HTTP_CF_CONNECTING_IP"]; + } + break; } - break; } } - + // Let people know that the CF WP plugin is turned on. if (!headers_sent()) { header("X-CF-Powered-By: WP " . CLOUDFLARE_VERSION); } - add_action('admin_menu', 'cloudflare_config_page'); - cloudflare_admin_warnings(); + add_action('admin_menu', 'cloudflare_config_page'); + cloudflare_admin_warnings(); } add_action('init', 'cloudflare_init',1); @@ -90,10 +105,29 @@ function cloudflare_conf() { global $cloudflare_api_key, $cloudflare_api_email, $is_cf; global $wpdb; + // get raw domain - may include www. + $urlparts = parse_url(site_url()); + $raw_domain = $urlparts["host"]; + + $curl_installed = function_exists('curl_init'); + + if ($curl_installed) { + // Attempt to get the matching host from CF + $domain = get_domain($cloudflare_api_key, $cloudflare_api_email, $raw_domain); + // If not found, default to pulling the domain via client side. + if (!$domain) { + $domain = $raw_domain; + } + } + else { + $domain = $raw_domain; + } + + define ("THIS_DOMAIN", $domain); + $db_results = array(); if ( isset($_POST['submit']) - && !($_POST['optimize']) && check_admin_referer('cloudflare-db-api','cloudflare-db-api-nonce') ) { if ( function_exists('current_user_can') && !current_user_can('manage_options') ) { @@ -102,6 +136,7 @@ function cloudflare_conf() { $key = $_POST['key']; $email = $_POST['email']; + $dev_mode = esc_sql($_POST["dev_mode"]); if ( empty($key) ) { $key_status = 'empty'; @@ -123,44 +158,33 @@ function cloudflare_conf() { update_option('cloudflare_api_email_set_once', "TRUE"); } + $messages = array( 'new_key_empty' => array('color' => 'aa0', 'text' => __('Your key has been cleared.')), 'new_key_valid' => array('color' => '2d2', 'text' => __('Your key has been verified. Happy blogging!')), 'new_email_empty' => array('color' => 'aa0', 'text' => __('Your email has been cleared.')), - 'new_email_valid' => array('color' => '2d2', 'text' => __('Your email has been verified. Happy blogging!')), + 'new_email_valid' => array('color' => '2d2', 'text' => __('Your email has been verified. Happy blogging!')) ); - } else if ( isset($_POST['submit']) - && isset($_POST['optimize']) - && check_admin_referer('cloudflare-db-opt','cloudflare-db-opt-nonce')) { - - update_option('cloudflare_api_db_last_run', time()); - if(current_user_can('administrator')) { - remove_action('admin_notices', 'cloudflare_warning'); - $tables = $wpdb->get_col("SHOW TABLES"); - foreach($tables as $table_name) { - $optimize = $wpdb->query("OPTIMIZE TABLE `$table_name`"); - $analyze = $wpdb->query("ANALYZE TABLE `$table_name`"); - if (!$optimize || !$analyze) { - $db_results[] = "Error optimizing $table_name"; + + if ($curl_installed) { + if ($key != "" && $email != "") { + set_dev_mode(esc_sql($key), esc_sql($email), THIS_DOMAIN, $dev_mode); + if ($dev_mode) { + $ms[] = 'dev_mode_on'; + } + else { + $ms[] = 'dev_mode_off'; } } - if (count($db_results) == 0) { - $db_results[] = "All tables optimized without error."; - } - } else { - $db_results[] = "The current user does not have the permission \"manage_database\". Please run the command again with an appropriate user."; + + $messages['dev_mode_on'] = array('color' => '2d2', 'text' => __('Development mode is On. Happy blogging!')); + $messages['dev_mode_off'] = array('color' => 'aa0', 'text' => __('Development mode is Off. Happy blogging!')); } } - ?> - +

-

+
@@ -186,8 +210,6 @@ function cloudflare_conf() {
  1. 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.
  2. -
  3. This plugin can also help to ensure your server database is running optimally. If you are going to run the Database Optimizer associated with this plugin, then run it at a low traffic time. While the Database Optimizer is running, your site will go into Read Only mode, which means that you or your visitors will not be allowed to post. The optimizer should run quickly. Once the optimizer is done running, you will be able to post to your site again. To run the Database Optimizer, click the icon below.
  4. -
  5. 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.
  6. We recommend that any user on CloudFlare with WordPress use this plugin.
  7. @@ -201,7 +223,9 @@ function cloudflare_conf() { 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.
    @@ -218,22 +242,20 @@ function cloudflare_conf() {

    (Get this?'); ?>)

    -

    (Get this?'); ?>)

    +

    (Get this?'); ?>) +

    (What is this?)

    -

    - + +
    + > Off + > On +
    + + You cannot toggle development mode because cURL is not installed for your domain. Please contact a server administrator for assistance with installing cURL. + - - -
    - - - -

    - (What is this?'); ?>)

    - +

    +

    ?> @@ -244,42 +266,7 @@ function cloudflare_conf() { function cloudflare_admin_warnings() { global $cloudflare_api_key, $cloudflare_api_email; - load_cloudflare_keys(); - - /** - if ( !get_option('cloudflare_api_key_set_once') && !$cloudflare_api_key && !isset($_POST['submit']) ) { - function cloudflare_warning() { - echo " -

    ".__('CloudFlare is almost ready.')." ".sprintf(__('You must enter your CloudFlare API key for it to work.'), "plugins.php?page=cloudflare")."

    - "; - } - add_action('admin_notices', 'cloudflare_warning'); - return; - } else if ( !get_option('cloudflare_api_key_set_once') && !$cloudflare_api_email && !isset($_POST['submit']) ) { - function cloudflare_warning() { - echo " -

    ".__('CloudFlare is almost ready.')." ".sprintf(__('You must enter your CloudFlare API email for it to work.'), "plugins.php?page=cloudflare")."

    - "; - } - add_action('admin_notices', 'cloudflare_warning'); - return; - } - */ - - // Check to see if they should optimized their DB - $last_run_time = (int)get_option('cloudflare_api_db_last_run'); - if (!$last_run_time) { - $last_run_time = time(); - } - if (time() - $last_run_time > 5259487) { // 2 Months (avg) - function cloudflare_warning() { - echo " -

    ".__('Your Database is due to be optimized again.')." ".sprintf(__('We recommend that you run the CloudFlare optimizer every two months to keep your blog running quickly. It\'s time to run it again.'), "plugins.php?page=cloudflare")."

    - "; - } - add_action('admin_notices', 'cloudflare_warning'); - return; - } + load_cloudflare_keys(); } // Now actually allow CF to see when a comment is approved/not-approved. @@ -321,4 +308,90 @@ function cloudflare_set_comment_status($id, $status) { add_action('wp_set_comment_status', 'cloudflare_set_comment_status', 1, 2); +function get_dev_mode_status($token, $email, $zone) { + $url = 'https://www.cloudflare.com/api_json.html'; + $fields = array( + 'a'=>"zone_load", + 'tkn'=>$token, + 'email'=>$email, + 'z'=>$zone + ); + + foreach($fields as $key=>$value) { + $fields_string .= $key.'='.$value.'&'; + } + rtrim($fields_string,'&'); + $ch = curl_init(); + curl_setopt($ch,CURLOPT_URL,$url); + curl_setopt($ch,CURLOPT_POST,count($fields)); + curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + $result = curl_exec($ch); + $result = json_decode($result); + curl_close($ch); + + if ($result->response->zone->obj->zone_status_class == "status-dev-mode") { + return "on"; + } + + return "off"; +} + +function set_dev_mode($token, $email, $zone, $value) +{ + $url = 'https://www.cloudflare.com/api_json.html'; + $fields = array( + 'a'=>"devmode", + 'tkn'=>$token, + 'email'=>$email, + 'z'=>$zone, + 'v'=>$value + ); + foreach($fields as $key=>$value) { + $fields_string .= $key.'='.$value.'&'; + } + rtrim($fields_string,'&'); + $ch = curl_init(); + curl_setopt($ch,CURLOPT_URL,$url); + curl_setopt($ch,CURLOPT_POST,count($fields)); + curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + $result = curl_exec($ch); + $result = json_decode($result); + curl_close($ch); +} + +function get_domain($token, $email, $raw_domain) { + $url = 'https://www.cloudflare.com/api_json.html'; + $fields = array( + 'a'=>"zone_load_multi", + 'tkn'=>$token, + 'email'=>$email + ); + + foreach($fields as $key=>$value) { + $fields_string .= $key.'='.$value.'&'; + } + rtrim($fields_string,'&'); + $ch = curl_init(); + curl_setopt($ch,CURLOPT_URL,$url); + curl_setopt($ch,CURLOPT_POST,count($fields)); + curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + $result = curl_exec($ch); + $result = json_decode($result); + curl_close($ch); + + $zone_count = $result->response->zones->count; + if ($zone_count > 0) { + for ($i = 0; $i < $zone_count; $i++) { + $zone_name = $result->response->zones->objs[$i]->zone_name; + if (strpos($raw_domain, $zone_name) !== FALSE){ + return $zone_name; + } + } + } + + return null; +} ?> diff --git a/cloudflare/ip_in_range.php b/cloudflare/ip_in_range.php index 0aad55a..e3b2498 100644 --- a/cloudflare/ip_in_range.php +++ b/cloudflare/ip_in_range.php @@ -27,6 +27,12 @@ * Please do not remove this header, or source attibution from this file. */ +/* +* Modified by James Greene to include IPV6 support +* (original version only supported IPV4). +* 21 May 2012 +*/ + // decbin32 // In order to simplify working with IP addresses (in binary) and their @@ -36,7 +42,7 @@ function decbin32 ($dec) { return str_pad(decbin($dec), 32, '0', STR_PAD_LEFT); } -// ip_in_range +// ipv4_in_range // This function takes 2 arguments, an IP address and a "range" in several // different formats. // Network ranges can be specified as: @@ -46,7 +52,7 @@ function decbin32 ($dec) { // The function will return true if the supplied IP is within the range. // Note little validation is done on the range inputs - it expects you to // use one of the above 3 formats. -function ip_in_range($ip, $range) { +function ipv4_in_range($ip, $range) { if (strpos($range, '/') !== false) { // $range is in IP/NETMASK format list($range, $netmask) = explode('/', $range, 2); @@ -93,4 +99,116 @@ function ip_in_range($ip, $range) { return false; } } + +function ip2long6($ip) { + if (substr_count($ip, '::')) { + $ip = str_replace('::', str_repeat(':0000', 8 - substr_count($ip, ':')) . ':', $ip); + } + + $ip = explode(':', $ip); + $r_ip = ''; + foreach ($ip as $v) { + $r_ip .= str_pad(base_convert($v, 16, 2), 16, 0, STR_PAD_LEFT); + } + + return base_convert($r_ip, 2, 10); +} + +// Get the ipv6 full format and return it as a decimal value. +function get_ipv6_full($ip) +{ + $pieces = explode ("/", $ip, 2); + $left_piece = $pieces[0]; + $right_piece = $pieces[1]; + + // Extract out the main IP pieces + $ip_pieces = explode("::", $left_piece, 2); + $main_ip_piece = $ip_pieces[0]; + $last_ip_piece = $ip_pieces[1]; + + // Pad out the shorthand entries. + $main_ip_pieces = explode(":", $main_ip_piece); + foreach($main_ip_pieces as $key=>$val) { + $main_ip_pieces[$key] = str_pad($main_ip_pieces[$key], 4, "0", STR_PAD_LEFT); + } + + // Check to see if the last IP block (part after ::) is set + $last_piece = ""; + $size = count($main_ip_pieces); + if (trim($last_ip_piece) != "") { + $last_piece = str_pad($last_ip_piece, 4, "0", STR_PAD_LEFT); + + // Build the full form of the IPV6 address considering the last IP block set + for ($i = $size; $i < 7; $i++) { + $main_ip_pieces[$i] = "0000"; + } + $main_ip_pieces[7] = $last_piece; + } + else { + // Build the full form of the IPV6 address + for ($i = $size; $i < 8; $i++) { + $main_ip_pieces[$i] = "0000"; + } + } + + // Rebuild the final long form IPV6 address + $final_ip = implode(":", $main_ip_pieces); + + return ip2long6($final_ip); +} + + +// Determine whether the IPV6 address is within range. +// $ip is the IPV6 address in decimal format to check if its within the IP range created by the cloudflare IPV6 address, $range_ip. +// $ip and $range_ip are converted to full IPV6 format. +// Returns true if the IPV6 address, $ip, is within the range from $range_ip. False otherwise. +function ipv6_in_range($ip, $range_ip) +{ + $pieces = explode ("/", $range_ip, 2); + $left_piece = $pieces[0]; + $right_piece = $pieces[1]; + + // Extract out the main IP pieces + $ip_pieces = explode("::", $left_piece, 2); + $main_ip_piece = $ip_pieces[0]; + $last_ip_piece = $ip_pieces[1]; + + // Pad out the shorthand entries. + $main_ip_pieces = explode(":", $main_ip_piece); + foreach($main_ip_pieces as $key=>$val) { + $main_ip_pieces[$key] = str_pad($main_ip_pieces[$key], 4, "0", STR_PAD_LEFT); + } + + // Create the first and last pieces that will denote the IPV6 range. + $first = $main_ip_pieces; + $last = $main_ip_pieces; + + // Check to see if the last IP block (part after ::) is set + $last_piece = ""; + $size = count($main_ip_pieces); + if (trim($last_ip_piece) != "") { + $last_piece = str_pad($last_ip_piece, 4, "0", STR_PAD_LEFT); + + // Build the full form of the IPV6 address considering the last IP block set + for ($i = $size; $i < 7; $i++) { + $first[$i] = "0000"; + $last[$i] = "ffff"; + } + $main_ip_pieces[7] = $last_piece; + } + else { + // Build the full form of the IPV6 address + for ($i = $size; $i < 8; $i++) { + $first[$i] = "0000"; + $last[$i] = "ffff"; + } + } + + // Rebuild the final long form IPV6 address + $first = ip2long6(implode(":", $first)); + $last = ip2long6(implode(":", $last)); + $in_range = ($ip >= $first && $ip <= $last); + + return $in_range; +} ?> \ No newline at end of file diff --git a/cloudflare/readme.txt b/cloudflare/readme.txt index 33b25a9..6f5b7ff 100644 --- a/cloudflare/readme.txt +++ b/cloudflare/readme.txt @@ -1,9 +1,9 @@ === CloudFlare === -Contributors: i3149, jchen329 +Contributors: i3149, jchen329, jamescf Tags: cloudflare, comments, spam, cdn, free, website, performance, speed Requires at least: 2.8 Tested up to: 3.3 -Stable tag: 1.2.2 +Stable tag: 1.3.6 License: GPLv2 The CloudFlare WordPress Plugin ensures your WordPress blog is running optimally on the CloudFlare platform. @@ -41,6 +41,23 @@ You will also want to sign up your blog with CloudFlare.com [Read more](http://blog.cloudflare.com/introducing-the-cloudflare-wordpress-plugin) on why we created this plugin. == Changelog == += 1.3.6 = +* Remove Database Optimizer. + += 1.3.5 = +* Disable Development Mode option if cURL not installed. Will Use JSONP in future release to allow domains without cURL to use Development Mode. + += 1.3.4 = +* Add in IPV6 support and Development Mode option to wordpress plugin settings page. Remove cached IP range text file. + += 1.3.3 = +* Bump stable version number. + += 1.3.2.Beta = +* BETA RELEASE: IPv6 support - Pull the IPv6 range from https://www.cloudflare.com/ips-v6. Added Development Mode option to wordpress plugin settings page. + += 1.2.4 = +* Pull the IP range from https://www.cloudflare.com/ips-v4. Modified to keep all files within cloudflare plugin directory. = 1.2.3 = * Updated with new IP range