nginx-ultimate-bad-bot-blocker/update-ngxblocker

346 lines
10 KiB
Bash
Executable file

#!/bin/sh
# Shell Script for Auto Updating the Nginx Bad Bot Blocker
# Copyright: https://github.com/mitchellkrogza
# Project Url: https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker
# Update script & Alpine Linux package by Stuart Cardall: https://github.com/itoffshore
# MAKE SURE you have all the following files in /etc/nginx/bots.d/ folder
# ***********************************************************************
# whitelist-ips.conf
# whitelist-domains.conf
# blacklist-user-agents.conf
# bad-referrer-words.conf
# custom-bad-referrers.conf
# blacklist-ips.conf
# A major change to using include files was introduced in
# https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/commit/7e3ab02172dafdd524de5dd450a9732328622779
# **************************************************************************
# Nginx will fail a reload with [EMERG] without the presence of these files.
# PLEASE READ UPDATED CONFIGURATION INSTRUCTIONS BEFORE USING THIS
# Save this file as /usr/sbin/update-ngxblocker
# cd /usr/sbin
# sudo wget https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/update-ngxblocker -O update-ngxblocker
# Make it Executable chmod 700 /usr/sbin/update-ngxblocker
# RUN THE UPDATE
# Here our script runs, pulls the latest update, reloads nginx and emails you a notification
EMAIL="me@myemail.com"
SEND_EMAIL="Y"
CONF_DIR=/etc/nginx/conf.d
BOTS_DIR=/etc/nginx/bots.d
INSTALLER=/usr/sbin/install-ngxblocker
##### end user configuration ##############################################################
BOLDGREEN="\033[1m\033[32m"
BOLDMAGENTA="\033[1m\033[35m"
BOLDRED="\033[1m\033[31m"
BOLDYELLOW="\033[1m\033[33m"
BOLDWHITE="\033[1m\033[37m"
RESET="\033[0m"
usage() {
local script=$(basename $0)
cat <<EOF
$script: UPDATE Nginx Bad Bot Blocker blacklist in: [ $CONF_DIR ]
Usage: $script [OPTIONS]
[ -c ] : NGINX conf directory (default: $CONF_DIR)
[ -b ] : NGINX bots directory (default: $BOTS_DIR)
[ -i ] : Change installer path (default: $INSTALLER)
[ -r ] : Change repo url (default: $REPO)
[ -e ] : Change email address (default: $EMAIL)
[ -n ] : Do not send email report (default: $SEND_EMAIL)
[ -v ] : Print blacklist version
[ -h ] : this help message
Examples:
$script (Download globalblacklist.conf to: $CONF_DIR)
$script -c /my/custom/conf.d (Download globalblacklist.conf to a custom location)
$script -b /my/custom/bots.d (Download globalblacklist.conf & update with your custom bots.d location)
$script -e yourname@youremailaddress.com (Download globalblacklist.conf specifying your email address for the notification)
$script -u /path/to/install-ngxblocker (Use custom path to install-ngxblocker to update bots.d / conf.d include files)
EOF
exit 0
}
check_version() {
local remote_ver= remote_date= version= date= file=$CONF_DIR/globalblacklist.conf
local tmp=$(mktemp) url=$REPO/conf.d/globalblacklist.conf range="145-345"
if [ -f $file ]; then
# local version
version=$(grep "Version:" $file | sed 's|^.*: V||g')
date=$(grep "Updated:" $file | sed 's|^.*: ||g')
printf "\nLOCAL Version: $BOLDWHITE$version$RESET\n"
printf "Updated: $date\n\n"
# remote version
curl -s --limit-rate 5k -r $range --location $url -o $tmp
remote_ver=$(grep "Version:" $tmp | sed 's|^.*: V||g')
remote_date=$(grep "Updated:" $tmp | sed 's|^.*: ||g')
printf "REMOTE Version: $BOLDWHITE$remote_ver$RESET\n"
printf "Updated: $remote_date\n"
rm -f $tmp
if [ "$version" != "$remote_ver" ]; then
printf "\nUpdate Available => $BOLDMAGENTA$remote_ver$RESET\n\n"
else
printf "\nLatest Blacklist Already Installed: $BOLDGREEN$version$RESET\n\n"
fi
else
printf "${BOLDRED}ERROR${RESET}: Missing '$file' => ${BOLDWHITE}running $INSTALLER:${RESET}\n"
$INSTALL_INC
if [ -f $file ]; then
check_version
fi
fi
exit 0
}
check_dirs() {
local x= dirs="$*"
for x in $dirs; do
if [ ! -d $x ]; then
printf "${BOLDRED}ERROR${RESET}: Missing directory: $x => ${BOLDWHITE}running $INSTALLER:${RESET}\n"
$INSTALL_INC
fi
done
}
update_paths() {
# variables in nginx include files not currently possible
# updates hard coded bots.d path in globalblacklist.conf
local blacklist=$1 include_paths= dir= x=
if ! grep "$BOTS_DIR" $blacklist 1>/dev/null; then
if [ -d $BOTS_DIR ]; then
printf "${BOLDGREEN}Updating bots.d path${RESET}: ${BOLDWHITE}$BOTS_DIR => $blacklist${RESET}\n"
include_paths=$(grep -E "include /.*.conf;$" $blacklist | awk '{print $2}' | tr -d ';')
for x in $include_paths; do
dir=$(dirname $x)
sed -i "s|$dir|$BOTS_DIR|" $blacklist
done
else
printf "${BOLDRED}ERROR${RESET}: '$BOTS_DIR' does not exist => ${BOLDWHITE}running $INSTALLER${RESET}.\n"
$INSTALL_INC
update_paths $blacklist
fi
fi
}
service_cmd() {
# arch linux does not have a 'service' command
local svc= svc_list="service systemctl rc-service"
for svc in $svc_list; do
svc=$(which $svc 2>/dev/null)
if [ -n "$svc" ]; then
echo $svc
exit 0
fi
done
}
sanitize_path() {
echo $1 |tr -cd '[:alnum:] [=@=] [=.=] [=-=] [=/=] [=_=]' \
|tr -s '@.-/_' |awk '{print tolower($0)}'
}
sanitize_url() {
echo $1 |tr -cd '[:alnum:] [=:=] [=.=] [=-=] [=/=]' \
|tr -s ':.-' |awk '{print tolower($0)}'
}
sanitize_email() {
echo $1 |tr -cd '[:alnum:] [=@=] [=.=] [=-=] [=_=]' \
|tr -s '@-_.' |awk '{print tolower($0)}'
}
check_args() {
local option=$1 type=$2 arg=$3
local msg="ERROR: option '-$option' argument '$arg' requires:"
case "$type" in
path) if ! echo $arg | grep ^/ 1>/dev/null; then
printf "$msg absolute path.\n"
exit 1
fi
;;
email) if ! echo $arg | grep -E ^[\.-_[:alnum:]]+@[\.-_[:alnum:]]+[\.][\.a-z]+ 1>/dev/null; then
printf "$msg email@domain.com\n"
exit 1
fi
;;
url) if ! echo $arg | grep -E ^http[s]?://[0-9a-zA-Z-]+[.]+[/0-9a-zA-Z.]+ 1>/dev/null; then
printf "$msg url => http[s]://the.url\n"
exit 1
fi
;;
script) if [ ! -x $arg ]; then
printf "$msg '$arg' is not executable / does not exist.\n"
exit 1
fi
;;
none) printf "$msg argument.\n"; exit 1;;
esac
}
check_mail_depends() {
if [ ! -f /usr/bin/mail ]; then # mailx + ssmtp are enough to send emails
printf "${BOLDYELLOW}WARN${RESET}: missing /usr/bin/mail => ${BOLDWHITE}disabling emails${RESET}.\n\n"
SEND_EMAIL="N"
fi
}
check_depends() {
# centos does not have wget installed by default
if ! wget --help >/dev/null 2>&1; then
printf "${BOLDRED}ERROR${RESET}: $0 requires: 'wget' => ${BOLDWHITE}cannot download files.${RESET}\n"
exit 1
fi
# centos also does not have which by default
if [ ! -x /usr/bin/curl ]; then
printf "${BOLDRED}ERROR${RESET}: $0 requires: 'curl' => ${BOLDWHITE}cannot check remote version.${RESET}\n"
exit 1
fi
# install-ngxblocker downloads missing scripts / includes as part of the update process
if [ ! -x $INSTALLER ]; then
printf "${BOLDRED}ERROR${RESET}: $0 requires: '$INSTALLER' => ${BOLDWHITE}cannot update includes.${RESET}\n"
exit 1
fi
}
get_options() {
local arg= opts=
while getopts :c:b:u:r:e:nvh opts "$@"
do
if [ -n "${OPTARG}" ]; then
case "$opts" in
r) arg=$(sanitize_url ${OPTARG});;
e) arg=$(sanitize_email ${OPTARG});;
*) arg=$(sanitize_path ${OPTARG});;
esac
fi
case "$opts" in
c) CONF_DIR=$arg; check_args $opts path $arg ;;
b) BOTS_DIR=$arg; check_args $opts path $arg ;;
i) INSTALLER=$arg; check_args $opts script $arg ;;
r) REPO=$arg; check_args $opts url $arg ;;
e) EMAIL=$arg; check_args $opts email $arg ;;
n) SEND_EMAIL=N ;;
v) check_depends; check_version ;;
h) usage ;;
\?) usage ;;
:) check_args $OPTARG none none ;;
esac
done
INSTALL_INC="$INSTALLER -b $BOTS_DIR -c $CONF_DIR -x"
}
main() {
local REPO=https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master
local file=globalblacklist.conf remote_dir=conf.d url= output= update= status= tmp= retval=
# default to service (centos does not have 'which' by default)
local service=${service_cmd:-"service"}
# require root
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
check_depends
# parse command line
get_options $@
check_dirs $BOTS_DIR $CONF_DIR
url=$REPO/$remote_dir/$file
output=$CONF_DIR/$file
# check for updated blacklist
update=$(check_version | tail -n 2)
printf "\n$update\n\n"
if echo $update | grep ^Update 1>/dev/null; then
# download globalblacklist update
tmp=$(mktemp)
mkdir -p $CONF_DIR
printf "${BOLDWHITE}Downloading: $file "
curl --fail --connect-timeout 60 --retry 10 --retry-delay 5 -so $tmp $url
retval=$?
case "$retval" in
0) printf "...${BOLDGREEN}OK${RESET}\n\n"
mv $tmp $output
;;
22) printf "...${BOLDRED}ERROR 404: $url${RESET}\n\n";;
28) printf "...${BOLDRED}ERROR TIMEOUT: $url${RESET}\n\n";;
*) printf "...${BOLDRED}ERROR CURL: ($retval){RESET}\n\n";;
esac
# download new bots.d / conf.d files
$INSTALL_INC
# set custom bots.d path
update_paths $output
# re-read nginx configuration
if [ $retval = 0 ]; then
$service nginx reload
if [ $? = 0 ]; then
status="${BOLDGREEN}[OK]${RESET}"
else
status="${BOLDRED}[FAILED]${RESET}"
fi
printf "\nReloading NGINX configuration...$status\n"
else
printf "\n${BOLDRED}Download failed${RESET}: not reloading NGINX config\n"
fi
else
# set custom bots.d path
update_paths $output
fi
# email report
check_mail_depends
case "$SEND_EMAIL" in
y*|Y*) printf "Emailing report to: ${BOLDWHITE}$EMAIL${RESET}\n\n";
# remove ansi colour codes
sed -i 's/\x1b\[[0-9;]*m//g' $EMAIL_REPORT
cat $EMAIL_REPORT | mail -s "Nginx Bad Bot Blocker Updated" $EMAIL
;;
esac
rm -f $EMAIL_REPORT
}
## start ##
EMAIL_REPORT=$(mktemp)
main $@ | tee $EMAIL_REPORT
exit $?
# Add this as a cron to run daily / weekly as you like
# Here's a sample CRON entry to update every day at 10pm
# 00 22 * * * sudo /usr/sbin/update-ngxblocker
# Here's another example to run it daily at midday using a command line switch to set the email address for the notification
# 00 12 * * * sudo /usr/sbin/update-ngxblocker -e yourname@youremailprovider.com
# better logging for cron jobs:
# https://serverfault.com/questions/137468/better-logging-for-cronjobs-send-cron-output-to-syslog