From 82282b528479e139b506b19b78ec09dda5d04c13 Mon Sep 17 00:00:00 2001 From: Stuart Cardall Date: Sat, 15 Apr 2017 19:24:48 +0000 Subject: [PATCH] add a setup script to insert the required includes the script will try to insert the new configuration below any existing includes in your config files. If the search string is not found the inserts are made at the end of the start search range: * for vhost files this is below the server_* directives. * for nginx.conf this is below http{ The search ranges & search string can be changed in main(). usage instructions can be found by running: setup-ngxblocker -h or --help by default running the script with no command line switches does a "dry run" & prints to stdout the files & includes it would change: setup-ngxblocker to actually make changes you need to run with -x: setup-ngxblocker -x --- setup-ngxblocker | 246 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100755 setup-ngxblocker diff --git a/setup-ngxblocker b/setup-ngxblocker new file mode 100755 index 000000000..a5d4bb01c --- /dev/null +++ b/setup-ngxblocker @@ -0,0 +1,246 @@ +#!/bin/sh + +### NGINX Bad Bot Blocker: setup script ################# +### Copyright (C) 2017 Stuart Cardall ### +### https://github.com/itoffshore ### +### Licensed under the terms of the GPL2 ### +########################################################## + +WWW=/var/www +VHOST_EXT="vhost" +VHOST_DIR=/etc/nginx/sites-available +BOTS_DIR=/etc/nginx/bots.d +CONF_DIR=/etc/nginx/conf.d +MAIN_CONF=/etc/nginx/nginx.conf +# setting Y / yes will whitelist only directories in $www +# that look like domain.names +DOT_NAMES="Y" +# if you already set 'limit_conn addr' you may want to set +# this to N / no. +INC_DDOS="Y" + +####### end user configuration ########################### + +usage() { + local script=$(basename $0) + cat < exiting." + exit 1 + fi +} + +find_vhosts() { + find $VHOST_DIR -type f -name "*.$VHOST_EXT" +} + +whitelist_ips() { + local ip= conf=$BOTS_DIR/whitelist-ips.conf + + mkdir -p $BOTS_DIR + + if [ -n "$(which dig)" ]; then + ip=$(dig +short myip.opendns.com @resolver1.opendns.com) + if ! grep "$ip" $conf &>/dev/null; then + printf "%-17s %-15s %-s\n" "Whitelisting ip:" "$ip" "=> $conf" + if [ "$DRY_RUN" = "N" ]; then + printf "%-23s %-s\n" "$ip" "0;" >> $conf + fi + fi + else + echo "WARN: dig binary missing => install bind-tools to whitelist external ip address" + fi +} + +whitelist_domains() { + local domain_list= domain= domain_len= + local conf=$BOTS_DIR/whitelist-domains.conf + + case "$DOT_NAMES" in + y*|Y*) domain_list=$(find $WWW -mindepth 1 -maxdepth 1 -type d -name '*\.*' -exec basename {} \;);; + *) domain_list=$(find $WWW -mindepth 1 -maxdepth 1 -type d -exec basename {} \;);; + esac + + domain_len=$(find $WWW -mindepth 1 -maxdepth 1 -type d -exec basename {} \; \ + | awk '{ print length ($0) }' | sort -nr | head -1) + + for domain in $domain_list; do + if ! grep "$domain" $conf &>/dev/null; then + printf "%-s %-$(( $domain_len +2))s %s\n" "Whitelisting domain:" "$domain" "=> $conf" + if [ "$DRY_RUN" = "N" ]; then + printf "%-$(( $domain_len +8))s %s\n" "\"~*$domain\"" "0;" >> $conf + fi + fi + done +} + +longest_str() { + echo $@ | tr " " "\n" | awk '{print length ($0)}' | sort -nr | head -n1 +} + +add_includes() { + local ph='<>' line=$1 file=$2 conf_dir=$3 text= update= + local include_list=$(echo $@ | awk '{$1=$2=$3=""}sub("^"OFS"+","")') + local col_size=$(( $(longest_str $include_list) + $(echo $conf_dir | wc -m) )) + + for text in $include_list; do + if ! grep "$text" $file 1>/dev/null; then + update='true' + text="include $conf_dir/$text;" + printf "%-10s %-$(( $col_size +10 ))s %s\n" "inserting:" "$text" "=> $file" + if [ "$DRY_RUN" = "N" ]; then + # $ph is just a placeholder so sed inserts a \t (tab) + sed -i "$line i $ph \t$text $ph" $file + fi + fi + done + + if [ "$DRY_RUN" = "N" ]; then + if [ -n "$update" ]; then + #add blank line below inserts + line=$(( $line + $(echo $include_list | wc -w) )) + if ! sed -n "${line}p" $file | grep ^'}' 1>/dev/null; then + text="include $conf_dir/$(echo $include_list | awk '{print $1}');" + sed -i "s|$text|$text\n|" $file + fi + + #add comment above inserts + text="include $conf_dir/$(echo $include_list | awk '{print $NF}');" + sed -i "s|$text|# Bad Bot Blocker\n\t$text|" $file + + # remove placeholders + sed -i "s|$ph||g" $file + fi + fi +} + +find_line() { + local file=$1 find_str=$2 first_last=$3 + + case "$first_last" in + first) awk "/$find_str/{ print NR; exit }" $file;; + last) awk "/$find_str/{ print NR }" $file | tail -n1;; + esac +} + +find_includes() { + local file=$1 search=$2 search_first_last=$3 line= tmp=$(mktemp) + local start_range=$4 start_first_last=$5 + local end_range=$6 end_first_last=$7 + local start=$(find_line $file $start_range $start_first_last) + local end=$(find_line $file $end_range $end_first_last) + + sed -n ${start},${end}p ${file} > $tmp + line=$(find_line $tmp $search $search_first_last) + rm -f $tmp + + # search string not found + if [ -z "$line" ]; then + line=1 + fi + + case "$search_first_last" in + first) line=$(( $line + $start -1 ));; + last) line=$(( $line + $start +1 ));; + esac + + # if inserting beyond the end of the file + if [ $line -gt $(wc -l < $file) ]; then + # insert blank line + sed -i "$end i \ " $file + fi + + echo $line +} + +get_options() { + local options=$(getopt -o w:e:v:b:c:m:ndhx --long \ + www:,ext:,vhost:,bots:,conf:,main:,names,ddos,help,exec -- "$@" 2>/dev/null) + + if [ $? -ne 0 ]; then + usage + exit 1 + fi + + eval set -- "$options" + + while :; do + case "$1" in + -h | --help) usage && exit 1;; + -x | --exec) DRY_RUN=N; shift;; + -w | --www) WWW=$2; shift 2;; + -e | --ext) VHOST_EXT=$2; shift 2;; + -v | --vhost) VHOST_DIR=$2; shift 2;; + -b | --bots) BOTS_DIR=$2; shift 2;; + -c | --conf) CONF_DIR=$2; shift 2;; + -m | --main) MAIN_CONF=$2; shift 2;; + -n | --names) DOT_NAMES=N; shift;; + -d | --ddos) INC_DDOS=N; shift;; + *) break;; + esac + done +} + +main() { + local file= line= vhost_includes= main_includes= file_list= + main_includes="botblocker-nginx-settings.conf globalblacklist.conf" + vhost_includes="blockbots.conf" + + # parse command line + get_options $@ + + case "$INC_DDOS" in + y*|Y*) vhost_includes="$vhost_includes ddos.conf" + esac + + file_list=$(find_vhosts) + check_config $file_list + + if [ -z "$DRY_RUN" ]; then + printf "\n** Dry Run ** | not updating files | -x or --exec to change files\n\n" + fi + + # update vhosts + for file in $file_list; do + line=$(find_includes $file include last server_ last location first ) + add_includes $line $file $BOTS_DIR $vhost_includes + done + + # update main config + line=$(find_includes $MAIN_CONF include last http first '\}' last ) + add_includes $line $MAIN_CONF $CONF_DIR botblocker-nginx-settings.conf globalblacklist.conf + + whitelist_ips + whitelist_domains +} + +## START ## +main $@ +exit $? +