Home   Projects   Layer 7 Dstat   Uptime

Introducing Cloudflare Auto UAM

Automate Cloudflare's Under Attack Mode with Ease!

Cloudflare Auto UAM is a simple Bash script designed for Unix systems that automatically enables or disables Cloudflare's "Under Attack Mode" based on specific conditions.
This script can help protect your website from DDoS attacks by automatically activating Cloudflare's security features when a threat is detected.

Source Code For Cloudflare Auto UAM Script:


#!/bin/bash
:'
@package		Auto Cloudflare UAM
@author			DSTAT (@DDoS_Filter)
@copyright		2024 DDoSFilter.Net
@file			/auto_uam.sh
@version		1.0
@comment		Public Release From DDoSFilter.Net With <3
@comment		https://www.ddosfilter.net/
*********************************************************************************
SETUP: (Based on stock apache2 install on ubuntu)
1.
In the terminal command line of your server type:
crontab -e
(If prompted to choose a text editor choose nano.)

2.
Paste this line (line 19) into the crontab and save: (Change directory to match your setup.)
*/1 * * * * /bin/bash /var/www/auto_uam.sh

3.
Press Ctrl + o
Press Enter
Press Ctrl + x

4.
Run this command in terminal:
nano /var/www/auto_uam.sh

5.
Paste this entire document into the terminal window.

6.
Press Ctrl + o
Press Enter
Press Ctrl + x

OR ||:
Manually add auto_uam.sh to the /var/www/ directory.

7.
Install jq and curl
sudo apt-get install jq curl -y

Done!
'

# Main Configuration
enable_cf_uam=true												# Enables UAM Via Cloudflare API | true/false
cf_connsec_threshold=100										# Minimum Requests Per Second To Trigger UAM
disable_rqst_sec=50												# Max Requests Per Second To Disable UAM
catpcha_active_time=300											# Minimum Time In Seconds To Display UAM After Activation
database='/var/www/auto_uam_database.json'						# Path To JSON Database
debug='/tmp/auto_uam_debug.log'									# Path To Save Debug Text File
http_log='/var/log/apache2/access.log'							# Path To HTTP Server Access Log

# Cloudflare Configuration
x_auth_email=''									# Cloudflare Email
x_auth_key=''									# Cloudflare API Authorization Key
zone_id=''										# Cloudflare Website Zone ID

# Function to enable/disable Cloudflare UAM
cf_enable_uam() {
	local bool=$1
	local url="https://api.cloudflare.com/client/v4/zones/$zone_id/settings/security_level"
	local auth_header=("X-Auth-Email: $x_auth_email" "X-Auth-Key: $x_auth_key" "Content-Type: application/json")
	local cf_data=''

	if [ "$bool" = true ]; then
		cf_data='{"value": "under_attack"}'
	else
		cf_data='{"value": "high"}'
		bool=false
	fi

	response=$(curl -s -X PATCH -H "X-Auth-Email: $x_auth_email" -H "X-Auth-Key: $x_auth_key" -H "Content-Type: application/json" -d "$cf_data" "$url")
	http_code=$(echo $response | jq -r '.success')

	if [ "$http_code" != "true" ]; then
		echo "$(date '+%B %d %Y %r') - CF API Request Failed Toggling UAM! Response: $response (Thread ID: $thread_id)" >> $debug
	else
		echo "$(date '+%B %d %Y %r') - CF UAM Enabled: $bool, Successful: $http_code (Thread ID: $thread_id)" >> $debug
		echo "$bool"
	fi
}

# Initial setup
loop_end=$(($(date +%s) + 60))
thread_id=$(date +%s)
echo "$(date '+%B %d %Y %r') - Started New Thread ($thread_id)" >> $debug

if [ ! -f "$database" ] || [ $(($(date +%s) - $(stat -c %Y "$database"))) -ge 86400 ]; then
	data='{"total_requests": 0, "last_requests": 0, "unix_time_stamp": 0, "time": "", "HTTP_Attack_Time": 0, "CF_UAM_Enabled": false}'
	echo "$(date '+%B %d %Y %r') - Built New Database! ($thread_id)" >> $debug
	echo "$data" > $database
fi

graph=$(cat "$database")
if [ -z "$graph" ]; then
	for i in {2..20}; do
		graph=$(cat "$database")
		if [ ! -z "$graph" ]; then
			echo "$(date '+%B %d %Y %r') - Error Reading Database, Read Database After $i Attempts! ($thread_id)" >> $debug
			break
		fi
		sleep 0.1
	done
	if [ -z "$graph" ]; then
		echo "$(date '+%B %d %Y %r') - Completely Failed To Read Database After $i Attempts! ($thread_id)" >> $debug
	fi
else
	echo "$(date '+%B %d %Y %r') - Read Database ($thread_id)" >> $debug
fi

echo "$(date '+%B %d %Y %r') - Beginning Data Loop ($thread_id)" >> $debug
last_requests=$(echo $graph | jq -r '.last_requests')

while [ $(date +%s) -le "$loop_end" ]; do
	start_time=$(date +%s.%N)
	this_requests=$(wc -l < $http_log)
	connections=$((this_requests - last_requests))

#	echo "$(date '+%B %d %Y %r') - This Requests: $this_requests, Last Requests: $last_requests, Connections: $connections" >> $debug

	if [ $connections -lt 0 ]; then
		connections=0
	fi

	# Update total_requests and other data
	data=$(echo $graph | jq ".total_requests += $connections | .last_requests = $this_requests | .unix_time_stamp = $(date +%s) | .time = \"$(date '+%r')\"")

	# Check if UAM should be disabled
	if [ "$enable_cf_uam" = true ] && [ $connections -le $disable_rqst_sec ]; then
		if [ $(($(date +%s) - $(echo $graph | jq -r '.HTTP_Attack_Time'))) -ge $catpcha_active_time ]; then
			if [ "$(echo $graph | jq -r '.CF_UAM_Enabled')" = "true" ]; then
				# Disable UAM
				uam_disabled=$(cf_enable_uam false)
				data=$(echo $data | jq --arg uam_disabled "$uam_disabled" '.CF_UAM_Enabled = ($uam_disabled == "true")')
			fi
		fi
	elif [ "$enable_cf_uam" != true ] && [ "$(echo $graph | jq -r '.CF_UAM_Enabled')" = "true" ]; then
		# Disable UAM if it shouldn't be enabled
		uam_disabled=$(cf_enable_uam false)
		data=$(echo $data | jq --arg uam_disabled "$uam_disabled" '.CF_UAM_Enabled = ($uam_disabled == "true")')
	fi

	if [ "$enable_cf_uam" = true ] && [ $connections -ge $cf_connsec_threshold ]; then
		if [ "$(echo $graph | jq -r '.CF_UAM_Enabled')" != "true" ]; then
			# Enable UAM
			uam_enabled=$(cf_enable_uam true)
			data=$(echo $data | jq --arg uam_enabled "$uam_enabled" --arg current_time "$(date +%s)" '.HTTP_Attack_Time = ($current_time | tonumber) | .CF_UAM_Enabled = ($uam_enabled == "true")')
		fi
	fi

	if [ -z "$(echo $data | jq 'select(.HTTP_Attack_Time != null and .CF_UAM_Enabled != null)')" ]; then
		echo "$(date '+%B %d %Y %r') - Found NULL Data, Skipped Writing To Database! ($thread_id)" >> $debug
	else
		echo $data > $database
		graph=$data  # Update the graph variable with the new data
	fi

	exec_time=$(echo "$(date +%s.%N) - $start_time" | bc)
	if (( $(echo "$exec_time < 1" | bc -l) )); then
		sleep $(echo "1 - $exec_time" | bc)
	else
		echo "$(date '+%B %d %Y %r') - Loop Overrun * Execution Time: $(echo $exec_time | awk '{printf "%.4f\n", $0}') ($thread_id)" >> $debug
	fi

	last_requests=$this_requests
done
echo "$(date '+%B %d %Y %r') - Finished Thread ($thread_id)" >> $debug