Cloudflare has upgraded their API to version 4 some while ago.

https://api.cloudflare.com/#user-level-firewall-access-rule-properties

I want to use the new APIs to block IP addresses using fail2ban. Using curl directly is a bit cumbersome, so I created a few php helper scripts. They can also be used in other projects.

Thanks to andrieslouw at github https://gist.github.com/andrieslouw/3c833332cbf66f95ca6751f82013acf5 I didn’t have to reinvent the wheel. He has created the backbones of the php scripts.

I’ve gone a bit further – I added a search where by supplying an IP address and the script can locate the object ID and delete it from the Firewall access list.

I also added some connection time-out and error checkings. They are not 100% nuclear-proof. Maybe you can help enhancing it.

Please note I am using “User Level” rules. On CF there are also Account and Organization level rule so you may need to amend the URL to suit your need.

There are 3 scripts:

  • cf_getaccesslist.php – dump the firewall access list in json format. This is good for checking your firewall or for debugging
  • cf_blockip.php – block an ip by supplying an ip address as argument
  • cf_unblockip.php – unblock an ip by supplying an ip address as argument

Simply amend the $authemail and $authkey in each script and run them in php. 

cf_getaccesslist.php

<?php

// Obtain a dump of the Cloudflare access list in json format
// Usage:
// php cf_getaccesslist.php


// Defining variables

$authemail = "[email protected]";
$authkey   = "YOUR-CLOUDFLARE-API-KEY";
$apiurl    = "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules";

$httphead  = array(
                   'X-Auth-Email: '.$authemail,
                   'X-Auth-Key: '.$authkey,
                   'Content-Type: application/json'
                  );

//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------

function getaccesslist() {

    global $httphead,$apiurl;

    $data  = array(
                    'match'=>'all',
                    'order'=>'mode',
                    'direction'=>'desc',
                   );
                        
                        
    // Build query string 
        
    $qrydata = http_build_query($data);

    // https://stackoverflow.com/questions/2138527/php-curl-http-post-sample-code

    $ch = curl_init();

    // We setup a http GET by the CURLOPT_URL option and provide an URL
    curl_setopt($ch, CURLOPT_URL, $apiurl."?".$qrydata);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $httphead);

    //Tell cURL that it should only spend 5 seconds
    //trying to connect to the URL in question.
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);

    //A given cURL operation should only take 5 seconds max.
    curl_setopt($ch, CURLOPT_TIMEOUT, 5);

    //Tell cURL to return the response output as a string.
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        
    // OK - go ahead and run curl
    $response = curl_exec($ch);

    curl_close($ch);

    //      Debug response
                echo $response;

    // if you wish to process the output further, 
    // the following line converts the json response into an associative array
        $r = json_decode($response, true);


}

//------------------------------------------------------------------------------------------

getaccesslist();

?>

cf_blockip.php

<?php

// Blocking an IP address on Cloudflare's firewall access rule
// Usage:
// cf_blockip.php [ipv4address]
// e.g.   php cf_unblock.php  192.168.10.200
// If successful it will return a status message

//---------------------------------------------------------------------------------------

$authemail = "[email protected]";
$authkey   = "YOUR-CLOUDFLARE-API-KEY";
$apiurl    = "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules";

$httphead  = array(
                   'X-Auth-Email: '.$authemail,
                   'X-Auth-Key: '.$authkey,
                   'Content-Type: application/json'
                  );

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

function cf_blockip($ipaddress) {

    global $httphead, $apiurl;

    $config    = array(
                       'target'=>'ip',
                       'value'=>$ipaddress
                      );

    $data      = array(
                       'mode'=>'block',
                       'configuration'=>$config,
                       'notes'=>'This is a block rule created by API4'
                      );

    $postdata = json_encode($data);
    //echo $postdata . "\r\n";

    // https://stackoverflow.com/questions/2138527/php-curl-http-post-sample-code

    // initialise curl
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $apiurl);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $httphead);
    
    // We setup a http POST, and provide %postdata
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);


    //Tell cURL that it should only spend 5 seconds
    //trying to connect to the URL in question.
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);

    //A given cURL operation should only take
    //5 seconds max.
    curl_setopt($ch, CURLOPT_TIMEOUT, 5);

    //Tell cURL to return the response output as a string.
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    // OK - go ahead and run curl
    $response = curl_exec($ch);

    curl_close($ch);

    //      Uncomment the following line to see $response
    //      echo $response;

    // convert $response to an associative array and place into $r
        $r = json_decode($response, true);

    //    $r['success'] holds a boolean value  - which is unprintable
    //      We will force the output of the boolean value using ? operator

    echo "Block status on IP " . $ipaddress ." : " . ($r['success'] ?  'True' : 'False');

        if ($r['success'] == False ) {
                echo " : ERROR : " .  $r['errors'][0]['message'];
        }

    echo "\r\n";
}

//---------------------------------------------------------------------------------------


// Getting IP input from argument
$ip =  $argv[1];

// call the function to block the ip
cf_blockip($ip);

?>

cf_unblockip.php

<?php

// Deleting an access rule on Cloudflare based on an IP address
// Usage:
// cf_unblockip.php [ipv4address]
// e.g.   php cf_unblock.php  192.168.10.200
// If successful it will return the ID of the CF access rule

// Defining variables

$authemail = "[email protected]";
$authkey   = "YOUR-CLOUDFLARE-API-KEY";
$apiurl    = "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules";

$httphead  = array(
                   'X-Auth-Email: '.$authemail,
                   'X-Auth-Key: '.$authkey,
                   'Content-Type: application/json'
                  );

//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------

function cfunban($block_rule_id){
// https://gist.github.com/andrieslouw/3c833332cbf66f95ca6751f82013acf5

    global  $httphead,$apiurl;

        $ch = curl_init();

        // We setup a special, http DELETE action 
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');

        curl_setopt($ch, CURLOPT_URL, $apiurl. "/". $block_rule_id);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $httphead);

        //Tell cURL that it should only spend 10 seconds
        //trying to connect to the URL in question.
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);

        //A given cURL operation should only take
        //30 seconds max.
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);

        //Tell cURL to return the response output as a string.
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        
        // OK - go ahead and run curl
        $return = curl_exec($ch);
        
        curl_close($ch);

        if ($return === false){
                return false;
        }else{
                $return = json_decode($return,true);
                if(isset($return['success']) && $return['success'] == true){
                        return $return['result']['id'];
                }else{
                        return false;
                }
        }
}

//------------------------------------------------------------------------------------------

function getcfid($ipaddress) {

    global $httphead,$apiurl;

    $data      = array(
                //'mode'=>'block',
                     'configuration.target'=>'ip',
                     'configuration.value'=>$ipaddress,
                  );

    // Build query string data
    $qrydata = http_build_query($data);

    // https://stackoverflow.com/questions/2138527/php-curl-http-post-sample-code

    $ch = curl_init();

    // We setup a http GET by the CURLOPT_URL option and provide an URL
        curl_setopt($ch, CURLOPT_URL, $apiurl."?".$qrydata);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $httphead);

        //Tell cURL that it should only spend 5 seconds
        //trying to connect to the URL in question.
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);

        //A given cURL operation should only take
        //5 seconds max.
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);

        //Tell cURL to return the response output as a string.
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        $response = curl_exec($ch);

        curl_close($ch);

    //      Debug response
    //        echo $response;

        $r = json_decode($response, true);


        if ($r['result_info']['count'] > 0) {

        //        echo $r['result'][0]['id'];
        return $r['result'][0]['id'];

        } else {
                die ("ERROR: The IP was not found in the list. \r\n");
        return False;
        }

}
//------------------------------------------------------------------------------------------


// Getting IP input
$ip =  $argv[1];

// Get the CF ID of the ip in the access list
$cfid=getcfid($ip);
echo "\r\n";

// Use the $cfid and delete the access rule
$result=cfunban($cfid);
echo $result;
echo "\r\n";

?>