Updating dynamic IP in Cloudflare WAF rule on Linux

In a previous post I showed you how to set up a WAF firewall which restricted access to the WordPress Admin (wp-admin) pages to secure make your WordPress site more secure.

In this post we will go over how you can set up a bash script on a Linux server to update that rule with your Public IP. The reason you may want to do this is because  if you are using Cloudflare as a proxy to your web server then when you want to go to WordPress Admin on your own network it will be displaying your Public IP and not your LAN IP.

First you'll have to log into your Cloudflare account and get your Zone ID which will be on the bottom right of the page.

Then you’ll need to get your Global API Key by clicking on “Get your API keys”>”Global API Key”>”View”.

You’ll have to run the following command on your Linux box so that you can get the Filter ID of the WAF rule since you may have multiple.

Finally you can take all the IDs and put them into the bash script below. This will look up your Public IPv4 and IPv6 addresses and update these on the Cloudflare WAF rule.

#!/bin/bash
ZoneID=123ZoneID
FilterID=123FilterID
[email protected]
AuthKey=123AuthKey

grep_ipv4 () {
        grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
}

grep_ipv6 () {
        egrep -o '(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))'
}


PublicIPv4="$(curl --silent checkip.dynu.com | grep_ipv4)";
echo "Public IPv4 is ${PublicIPv4}"
PublicIPv6="$(curl --silent checkipv6.dynu.com | grep_ipv6)";
echo "Public IPv6 is ${PublicIPv6}"

CloudflareIPs="$(curl --silent -X GET "https://api.cloudflare.com/client/v4/zones/${ZoneID}/filters/${FilterID}" \
     -H "X-Auth-Email: ${AuthEmail}" \
     -H "X-Auth-Key: ${AuthKey}" \
     -H "Content-Type: application/json")";
CloudflareIPv4=$(echo "${CloudflareIPs}" | grep_ipv4);
echo "Cloudflare firewall rule IPv4 is ${CloudflareIPv4}"
CloudflareIPv6=$(echo "${CloudflareIPs}" | grep_ipv6);
echo "Cloudflare firewall rule IPv6 is ${CloudflareIPv6}"

update_cloudflare () {
        curl -X PUT "https://api.cloudflare.com/client/v4/zones/${ZoneID}/filters" \
                -H "X-Auth-Email: ${AuthEmail}" \
                -H "X-Auth-Key: ${AuthKey}" \
                -H "Content-Type: application/json" \
        -d '[
 {
  "id": "'$FilterID'",
  "paused": false,
  "expression": "(not ip.src in {'$PublicIPv6' '$PublicIPv4'} and http.request.full_uri contains \"https://www.example.com/wp-admin/\")",
  "description": "IP update"
 }
]'
}

if [ "$PublicIPv4" = "$CloudflareIPv4" ]
then
        echo "IPv4 the same, no change being made"
        if [ "$PublicIPv6" = "$CloudflareIPv6" ]
        then
                echo "IPv6 the same, no change being made"
        else
                echo "IPv6 different, updating Cloudflare firewall rule IP"
                update_cloudflare
        fi
else
        echo "IPv4 different, updating Cloudflare firewall rule IP"
        update_cloudflare
fi

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.