mirror of
https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker.git
synced 2025-04-16 14:59:11 +00:00
* Amazon Linux puts pidof under /sbin fixes https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/issues/399
456 lines
14 KiB
Bash
Executable file
456 lines
14 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/local/sbin/update-ngxblocker
|
|
# cd /usr/local/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/local/sbin/update-ngxblocker
|
|
|
|
# RUN THE UPDATE
|
|
# Here our script runs, pulls the latest update, reloads nginx and emails you a notification
|
|
|
|
EMAIL="you@example.com"
|
|
SEND_EMAIL="N"
|
|
SEND_MG_EMAIL="N"
|
|
SEND_EMAIL_UPDATE="N"
|
|
#Mailgun
|
|
MG_API_KEY="key-yadayadayada"
|
|
MG_DOMAIN="mg.example.com"
|
|
MG_FROM=""
|
|
CONF_DIR=/etc/nginx/conf.d
|
|
BOTS_DIR=/etc/nginx/bots.d
|
|
INSTALLER=/usr/local/sbin/install-ngxblocker
|
|
LOGGING="N"
|
|
|
|
##### 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"
|
|
OS=$(uname -s)
|
|
CURL_PATH=""
|
|
|
|
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)
|
|
[ -g ] : Change @email address Mailgun (default: $EMAIL)
|
|
[ -d ] : Mailgun Domain
|
|
[ -a ] : Mailgun API Key
|
|
[ -f ] : Mailgun / Mail From Address
|
|
[ -m ] : Change mail (system alias) (default: $EMAIL)
|
|
[ -n ] : Do not send email report (default: $SEND_EMAIL)
|
|
[ -o ] : Only send email on update (default: $SEND_EMAIL_UPDATE)
|
|
[ -q ] : Suppress non error messages
|
|
[ -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 you@example.com (Download globalblacklist.conf specifying your email address for the notification)
|
|
$script -g you@example.com -d domain -a mailgunapikey -f fromaddress (Download globalblacklist.conf specifying your email address for the notification sent via mailgun)
|
|
$script -q -m webmaster (Send mail to a system alias address & give less verbose messages for cron)
|
|
$script -o -e you@example.com (Send mail notification only on updates)
|
|
$script -i /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_CMD} 's|^.*: V||g')
|
|
date=$(grep "Updated:" $file | ${SED_CMD} 's|^.*: ||g')
|
|
print_message "\nLOCAL Version: $BOLDWHITE$version$RESET\n"
|
|
print_message "Updated: $date\n\n"
|
|
# remote version
|
|
$CURL_PATH -s --limit-rate 5k -r $range --location $url -o $tmp
|
|
remote_ver=$(grep "Version:" $tmp | ${SED_CMD} 's|^.*: V||g')
|
|
remote_date=$(grep "Updated:" $tmp | ${SED_CMD} 's|^.*: ||g')
|
|
print_message "REMOTE Version: $BOLDWHITE$remote_ver$RESET\n"
|
|
print_message "Updated: $remote_date\n"
|
|
rm -f $tmp
|
|
|
|
if [ "$version" != "$remote_ver" ]; then
|
|
print_message "\nUpdate Available => $BOLDMAGENTA$remote_ver$RESET\n\n"
|
|
return 1
|
|
else
|
|
print_message "\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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
find_binary() {
|
|
local x= path= binary=$1 bin_paths='/bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/local/sbin /root/bin /root/.bin'
|
|
|
|
for x in $bin_paths; do
|
|
path="$x/$binary"
|
|
|
|
if [ -x $path ]; then
|
|
echo $path
|
|
return
|
|
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_CMD} -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
|
|
}
|
|
|
|
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:]]+ 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_depends() {
|
|
# global var is needed here, it is used in other places
|
|
CURL_PATH=$(find_binary curl)
|
|
|
|
case $OS in
|
|
Linux)
|
|
SED_CMD=$(find_binary sed)
|
|
;;
|
|
*BSD)
|
|
SED_CMD=$(find_binary gsed)
|
|
;;
|
|
esac
|
|
|
|
# centos does not have which by default
|
|
if [ -z $CURL_PATH ]; 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
|
|
}
|
|
|
|
print_message() {
|
|
local msg="$@"
|
|
|
|
if [ "$VERBOSE" != "N" ]; then
|
|
printf "$msg"
|
|
fi
|
|
}
|
|
|
|
log_output() {
|
|
local logger=$(find_binary logger)
|
|
local script=$(basename $0)
|
|
|
|
if [ -n "$logger" ]; then
|
|
# remove ansi color codes
|
|
${SED_CMD} -i 's/\x1b\[[0-9;]*m//g' $EMAIL_REPORT
|
|
# remove blank lines
|
|
${SED_CMD} -i '/^\s*$/d' $EMAIL_REPORT
|
|
# log output
|
|
$logger -t $script -f $EMAIL_REPORT 2>&1
|
|
print_message "Output logged to syslog\n";
|
|
else
|
|
print_message "${BOLDRED}ERROR: cannot find logger${RESET}\n\n";
|
|
fi
|
|
}
|
|
|
|
send_email() {
|
|
# email report (mailx + ssmtp are enough to send emails)
|
|
local mail_path=$(find_binary mail)
|
|
|
|
if [ -n "$mail_path" ]; then
|
|
print_message "Emailing report to: ${BOLDWHITE}$EMAIL${RESET}\n\n";
|
|
|
|
# remove ansi colour codes
|
|
${SED_CMD} -i 's/\x1b\[[0-9;]*m//g' $EMAIL_REPORT
|
|
|
|
if [ -n "$MG_FROM" ]; then
|
|
cat $EMAIL_REPORT | $mail_path -f "$MG_FROM" -s "Nginx Bad Bot Blocker Updated" $EMAIL
|
|
else
|
|
cat $EMAIL_REPORT | $mail_path -s "Nginx Bad Bot Blocker Updated" $EMAIL
|
|
fi
|
|
else
|
|
print_message "${BOLDYELLOW}WARN${RESET}: missing mail command => ${BOLDWHITE}disabling emails${RESET}.\n\n"
|
|
fi
|
|
}
|
|
|
|
send_email_via_mailgun() {
|
|
local report= subject= endpoint="https://api.mailgun.net/v3/$MG_DOMAIN/messages"
|
|
|
|
echo "Mailgunning report to: ${BOLDWHITE}$EMAIL${RESET}\n\n";
|
|
${SED_CMD} -i 's/\x1b\[[0-9;]*m//g' $EMAIL_REPORT
|
|
report="$(cat $EMAIL_REPORT)"
|
|
subject='Nginx Bad Bot Blocker Updated'
|
|
|
|
$CURL_PATH -s --user api:$MG_API_KEY $endpoint -F from='botblocker<'$MG_FROM'>' -F to=$EMAIL -F subject="$subject" -F text="$report"
|
|
}
|
|
|
|
get_options() {
|
|
local arg= opts=
|
|
|
|
while getopts :c:b:i:r:e:g:a:d:f:m:lnovqh opts "$@"
|
|
do
|
|
if [ -n "${OPTARG}" ]; then
|
|
case "$opts" in
|
|
r) arg=$(sanitize_url ${OPTARG});;
|
|
e) arg=$(sanitize_email ${OPTARG});;
|
|
g) 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; SEND_EMAIL=Y; check_args $opts email $arg ;;
|
|
g) EMAIL=$arg; SEND_MG_EMAIL=Y; check_args $opts email $arg ;;
|
|
a) MG_API_KEY=$arg;;
|
|
d) MG_DOMAIN=$arg;;
|
|
f) MG_FROM=$arg;;
|
|
m) EMAIL=$arg; SEND_EMAIL=Y ;; # /etc/aliases no sanity checks
|
|
l) LOGGING=Y ;;
|
|
n) SEND_EMAIL=N ;;
|
|
o) SEND_EMAIL_UPDATE=Y ;;
|
|
v) check_version; exit 0 ;;
|
|
q) export VERBOSE=N ;;
|
|
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=
|
|
local nginx_path=$(find_binary nginx)
|
|
local pidof_path=$(find_binary pidof)
|
|
|
|
# require root
|
|
if [ "$(id -u)" != "0" ]; then
|
|
echo "This script must be run as root" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# parse command line
|
|
get_options $@
|
|
check_depends
|
|
check_dirs $BOTS_DIR $CONF_DIR
|
|
url=$REPO/$remote_dir/$file
|
|
output=$CONF_DIR/$file
|
|
|
|
# check for updated blacklist
|
|
check_version
|
|
update=$?
|
|
|
|
if [ $update = 1 ]; then
|
|
|
|
# download globalblacklist update
|
|
tmp=$(mktemp)
|
|
mkdir -p $CONF_DIR
|
|
local dl_msg="${BOLDWHITE}Downloading: $file "
|
|
$CURL_PATH --fail --connect-timeout 60 --retry 10 --retry-delay 5 -so $tmp $url
|
|
retval=$?
|
|
|
|
case "$retval" in
|
|
0) print_message "$dl_msg...${BOLDGREEN}[OK]${RESET}\n\n"
|
|
mv $tmp $output
|
|
;;
|
|
22) printf "$dl_msg...${BOLDRED}ERROR 404: $url${RESET}\n\n";;
|
|
28) printf "$dl_msg...${BOLDRED}ERROR TIMEOUT: $url${RESET}\n\n";;
|
|
*) printf "$dl_msg...${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
|
|
|
|
# use full paths to workaround crontabs without $PATH configured
|
|
if $pidof_path nginx 1>/dev/null; then
|
|
|
|
$nginx_path -s reload 2>&1 >/dev/null
|
|
|
|
if [ $? = 0 ]; then
|
|
status="${BOLDGREEN}[OK]${RESET}"
|
|
print_message "\nReloading NGINX configuration...$status\n"
|
|
else
|
|
status="${BOLDRED}[FAILED]${RESET}"
|
|
printf "\nReloading NGINX configuration...$status\n"
|
|
fi
|
|
else
|
|
printf "\n${BOLDRED}NGINX is not running${RESET}: not reloading NGINX config\n"
|
|
fi
|
|
else
|
|
printf "\n${BOLDRED}Download failed${RESET}: not reloading NGINX config\n"
|
|
fi
|
|
|
|
# in silent mode print a single message after an update
|
|
if [ "$VERBOSE" = "N" ]; then
|
|
printf "NGINX Blacklist updated =>$(grep "Version:" $CONF_DIR/globalblacklist.conf | tr -d '#')\n"
|
|
fi
|
|
|
|
# enable update only email
|
|
if [ "$SEND_EMAIL_UPDATE" = "Y" ] ; then
|
|
SEND_EMAIL=Y
|
|
fi
|
|
|
|
else
|
|
# set custom bots.d path
|
|
update_paths $output
|
|
|
|
# disable update only email
|
|
if [ "$SEND_EMAIL_UPDATE" = "Y" ] ; then
|
|
SEND_EMAIL=N
|
|
fi
|
|
fi
|
|
|
|
# email report
|
|
case "$SEND_EMAIL" in
|
|
y*|Y*) send_email;;
|
|
esac
|
|
# email report via mailgun
|
|
case "$SEND_MG_EMAIL" in
|
|
y*|Y*) send_email_via_mailgun;;
|
|
esac
|
|
|
|
# log report
|
|
case "$LOGGING" in
|
|
y*|Y*) log_output;;
|
|
esac
|
|
}
|
|
|
|
## start ##
|
|
EMAIL_REPORT=$(mktemp)
|
|
main $@ | tee $EMAIL_REPORT
|
|
rm -f $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/local/sbin/update-ngxblocker -q
|
|
|
|
# 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/local/sbin/update-ngxblocker -e yourname@youremailprovider.com
|
|
|
|
# Less verbose logging to a system alias mail address (root crontab)
|
|
# 00 12 * * * /usr/local/sbin/update-ngxblocker -q -m webmaster
|
|
|
|
# better logging for cron jobs:
|
|
# https://serverfault.com/questions/137468/better-logging-for-cronjobs-send-cron-output-to-syslog
|