Created
April 9, 2019 12:33
-
-
Save ankitraturi/8714e4d8a234de4acc5d1e8e6840abf0 to your computer and use it in GitHub Desktop.
DDoS Mitigation Script: ban, unban and list IP to CloudFlare via API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| ############################################################################## | |
| # DDoS Mitigation Script: ban, unban and list IP to CF via API # | |
| # # | |
| ############################################################################## | |
| #TODO:: set ddosP in system path | |
| load_conf() | |
| { | |
| CONF="/usr/local/ddos/ddosP.conf" | |
| if [ -f "$CONF" ] && [ ! "$CONF" == "" ]; then | |
| source $CONF | |
| else | |
| head | |
| echo "\$CONF not found." | |
| exit 1 | |
| fi | |
| } | |
| TMP_PREFIX='/tmp/ddos' | |
| TMP_FILE="mktemp $TMP_PREFIX.XXXXXXXX" | |
| head() | |
| { | |
| echo | |
| echo "DDoS-Prevention" | |
| echo "================================================" | |
| echo "Block, unblock, list IP in Cloudflare" | |
| echo "Author: Ankit Raturi" | |
| echo "================================================" | |
| echo | |
| } | |
| showhelp() | |
| { | |
| head | |
| echo 'Usage: ddosIP.sh [OPTIONS] [N]' | |
| echo 'N : number of tcp/udp connections (default 150)' | |
| echo | |
| echo 'OPTIONS:' | |
| echo ' -h | --help : Show this help screen' | |
| echo ' -k | --kill : Block the offending IPs making more than N connections' | |
| echo ' -b | --block : Blocks the IP, add after a space' | |
| #echo ' -un | --unblock : Unblocks the IP, add after a space' | |
| #echo ' -l | --list : list of the blocked IPs' | |
| echo ' -z | --zones : list the zones in CloudFlare' | |
| echo | |
| } | |
| block_ip() | |
| { | |
| block_ip_cf "$1" | |
| echo $1 >> /usr/local/ddos/block.ip.list | |
| echo "blocked: $1" | |
| exit | |
| } | |
| block_ip_cf() | |
| { | |
| #block the IP from CloudFlare | |
| CURR_DATE=`date -d '1 minute ago' +%d/%b/%Y:%H:%M` | |
| #curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/firewall/ua_rules" -H "X-Auth-Email: $CF_EMAIL" -H "X-Auth-Key: $CF_AUTH_KEY" -H "Content-Type: application/json" --data '{"description":"Added to CF @ '"$curr_date"'","mode":"block","configuration":{"target":"ua","value":"'"$1"'"}}' > /dev/null | |
| #curl -sSX POST "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules" -H "X-Auth-Email: $CF_EMAIL" -H "X-Auth-Key: $CF_AUTH_KEY" -H "Content-Type: application/json" --data "{\"mode\":\"block\",\"configuration\":{\"target\":\"ip\",\"value\":\"$1\"},\"notes\":\"Blocked via cf_ban script"}" > /usr/local/ddos/testlog.txt | |
| curl -sSX POST "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules" \ | |
| -H "X-Auth-Email: $CF_EMAIL" \ | |
| -H "X-Auth-Key: $CF_AUTH_KEY" \ | |
| -H "Content-Type: application/json" \ | |
| --data "{\"mode\":\"block\",\"configuration\":{\"target\":\"ip\",\"value\":\"$1\"},\"notes\":\"Blocked via cf_ban script\"}" > /dev/null | |
| #cat /usr/local/ddos/testlog.txt | |
| return; | |
| } | |
| unblock_ip_cf() | |
| { | |
| TMP_PREFIX='/tmp/ddos' | |
| TMP_FILE="mktemp $TMP_PREFIX.XXXXXXXX" | |
| IP_ID=`$TMP_FILE` | |
| get_cf_zones #call function to get CF Zones | |
| while read line; do | |
| ZONE_ID=`echo $line | sed -e 's/^"//' -e 's/"$//'` | |
| #get IP id from CF api using IP string passed in $1 | |
| curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/firewall/ua_rules?page=1&per_page=20" -H "X-Auth-Email: $CF_EMAIL" -H "X-Auth-Key: $CF_AUTH_KEY" -H "Content-Type: application/json" | jq '.result[] | select ((.mode=="block") and .configuration.value=='"\"$1\""') | "\(.id)"' > $IP_ID | |
| CF_ID=`cat $IP_ID | sed -e 's/^"//' -e 's/"$//'` #assign output to a new variable and sed for removing double quotes | |
| if [ -z "$IP_ID" ]; then #check if IP is not found in CF | |
| echo 'No IP rule defined' | |
| continue | |
| else | |
| #unblock IP from id if found | |
| curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/firewall/ua_rules/$CF_ID" -H "X-Auth-Email: $CF_EMAIL" -H "X-Auth-Key: $CF_AUTH_KEY" -H "Content-Type: application/json" > /dev/null | |
| echo "unblocked IP for $ZONE_ID : $1" | |
| continue | |
| fi | |
| done < $zone_identifier | |
| ip_unblocked=$(echo $1 | sed 's/\//\\\//g') | |
| #echo $ip_unblocked | |
| sed -i '/$ip_unblocked/d' /usr/local/ddos/block.ip.list | |
| exit | |
| } | |
| get_ip_rules_cf() | |
| { | |
| CF_LIST=`$TMP_FILE` | |
| RESULT_LIST=`$TMP_FILE` | |
| # Get results from CF API using curl | |
| # -s for silent progress | |
| # jq for parsing json in shell script | |
| # store output to $CF_LIST | |
| curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ES_ZONE_ID/firewall/ua_rules?page=1&per_page=20" -H "X-Auth-Email: $CF_EMAIL" -H "X-Auth-Key: $CF_AUTH_KEY" -H "Content-Type: application/json" | jq '.result[] | select (.mode=="block") | "\(.configuration.value)"' > $CF_LIST | |
| # print CF IP list | |
| cat $CF_LIST | |
| exit | |
| } | |
| get_zones() | |
| { | |
| get_cf_zones | |
| while read line; do | |
| ZONE_ID=`echo $line | sed -e 's/^"//' -e 's/"$//'` | |
| echo "$ZONE_ID" | |
| continue | |
| done < $zone_identifier | |
| exit | |
| } | |
| get_cf_zones() | |
| { | |
| TMP_PREFIX='/tmp/ddos' | |
| TMP_FILE="mktemp $TMP_PREFIX.XXXXXXXX" | |
| zone_identifier=`$TMP_FILE` | |
| ZONE_IDS=`$TMP_FILE` | |
| curl -s -X GET "https://api.cloudflare.com/client/v4/zones" -H "X-Auth-Email: $CF_EMAIL" -H "X-Auth-Key: $CF_AUTH_KEY" -H "Content-Type: application/json" | jq '.result[] | "\(.id)"' > $zone_identifier | |
| #ZONE_IDS=`cat $zone_identifier | sed -e 's/^"//' -e 's/"$//'` | |
| } | |
| load_conf | |
| while [ $1 ]; do | |
| case $1 in | |
| '-h' | '--help' | '?' ) | |
| showhelp | |
| exit | |
| ;; | |
| '--cron' | '-c' ) | |
| add_to_cron | |
| exit | |
| ;; | |
| '--kill' | '-k' ) | |
| KILL=1 | |
| ;; | |
| '--block' | '-b' ) | |
| block_ip "$2" | |
| ;; | |
| '--unblock' | '-un' ) | |
| unblock_ip_cf "$2" | |
| ;; | |
| '--list' | '-l' ) | |
| get_ip_rules_cf | |
| ;; | |
| '--zones' | '-z' ) | |
| get_zones | |
| ;; | |
| *[0-9]* ) | |
| NO_OF_CONNECTIONS_IP=$1 | |
| ;; | |
| * ) | |
| showhelp | |
| exit | |
| ;; | |
| esac | |
| shift | |
| done | |
| TMP_PREFIX='/tmp/ddos' | |
| TMP_FILE="mktemp $TMP_PREFIX.XXXXXXXX" | |
| BANNED_IP_MAIL=`$TMP_FILE` | |
| BANNED_IP_LIST=`$TMP_FILE` | |
| echo "Banned the following Non-concurrent IPs on `date`" > $BANNED_IP_MAIL | |
| echo >> $BANNED_IP_MAIL | |
| BAD_IP_LIST=`$TMP_FILE` | |
| #get date format | |
| CURR_DATE=`date -d '1 minute ago' +%d/%b/%Y:%H:%M` | |
| #grep $CURR_DATE /var/www/vhosts/system/*/logs/access_log | awk -F\" '{print $6}' | sort | uniq -c | sort -rn > /usr/local/ddos/bad_ip_list | |
| grep $CURR_DATE /var/www/vhosts/system/*/logs/access* | awk '{print $2}' | sort | uniq -c | sort -nr > /usr/local/ddos/bad_ip_list_2 | |
| cat /usr/local/ddos/bad_ip_list_2 | mail -s "IPs banneds on $CURR_DATE" "ankitraturi@mailinator.com" | |
| #cat /usr/local/ddos/bad_ip_list_2 | |
| if [ $KILL -eq 1 ]; then | |
| IP_BAN_NOW=0 | |
| while read line; do | |
| #if no of connections is less than defined then ignore | |
| #echo $line | |
| #exit | |
| CURR_LINE_CONN=$(echo $line | cut -d " " -f1) | |
| #echo $NO_OF_CONNECTIONS_IP | |
| #exit | |
| CURR_LINE_IP=$(echo $line | cut -d " " -f2-) | |
| if [ $CURR_LINE_CONN -lt $NO_OF_CONNECTIONS_IP ]; then | |
| ###break | |
| #echo "less $CURR_LINE_CONN" | |
| continue | |
| fi | |
| #echo $CURR_LINE_IP | |
| #continue | |
| #ignore IP (good bots) | |
| IGNORE_IP=`grep -c "$CURR_LINE_IP" "$IGNORE_IP_LIST"` | |
| if [ $IGNORE_IP -ge 1 ]; then | |
| echo $CURR_LINE_IP | |
| continue | |
| fi | |
| #echo "here" | |
| #exit | |
| #ignore already added IP | |
| IGNORE_IP_2=`grep -c "$CURR_LINE_IP" "$BLOCK_IP_LIST"` | |
| if [ $IGNORE_IP_2 -ge 1 ]; then | |
| echo "Ignored: $CURR_LINE_IP" | |
| continue | |
| fi | |
| #echo "here" | |
| #continue | |
| #ignores if match the string | |
| flagkey=0 | |
| while read line; do | |
| if `echo ${CURR_LINE_IP} | grep -i "${line}" 1>/dev/null 2>&1` | |
| then | |
| echo "Ignored with matched keyword ( $line ) : $CURR_LINE_IP" | |
| flagkey=1 | |
| break | |
| fi | |
| done < $IGNORE_IP_KEYWORDS | |
| #echo $CURR_LINE_IP | |
| #exit | |
| if [ $flagkey -eq 1 ]; then | |
| continue | |
| fi | |
| #End: ignore IPs if match the string | |
| IP_BAN_NOW=1 | |
| echo "matched: $CURR_LINE_IP" | |
| #call block IP function | |
| $CURR_LINE_IP >> /usr/local/ddos/block.ip.list | |
| block_ip_cf "$CURR_LINE_IP" | |
| #email list to the admin | |
| echo "$CURR_LINE_IP with $CURR_LINE_CONN connections" >> $BANNED_IP_MAIL | |
| continue | |
| done < /usr/local/ddos/bad_ip_list_2 | |
| if [ $IP_BAN_NOW -eq 1 ]; then | |
| dt=`date` | |
| if [ $EMAIL_TO != "" ]; then | |
| cat $BANNED_IP_MAIL | mail -s "Non-Concurrent IP banned on $dt" $EMAIL_TO | |
| fi | |
| fi | |
| fi | |
| exit | |
| rm -f $TMP_PREFIX.* | |
| echo "RUN"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment