feature/ss-instead-of-netstat #2
					 1 changed files with 176 additions and 174 deletions
				
			
		|  | @ -3,7 +3,7 @@ | |||
| #                                                                              # | ||||
| # Try and prevent apache overloads by banning IP addresses that have (too)     # | ||||
| # many open connections.                                                       # | ||||
| # This script uses netstat to determine the connections to a configurable port # | ||||
| # This script uses ss to determine the connections to a configurable port      # | ||||
| # on the host machine and provides automated GeoIP information retrieval based # | ||||
| # the address or the /24-, /16- or /8-subnet thereof. A GeoIP city- or country # | ||||
| # database must be installed separately and is provided to the script via a    # | ||||
|  | @ -26,8 +26,8 @@ | |||
| #   - net-analyzer/fail2ban (`fail2ban-client`)                                # | ||||
| #   - sys-apps/coreutils (`cut`, `id`, `sort`, `touch`, `tr`, `uniq`)          # | ||||
| #   - sys-apps/grep (`grep`)                                                   # | ||||
| #   - sys-apps/iproute2 (`ss`)                                                 # | ||||
| #   - sys-apps/moreutils (`sponge`)                                            # | ||||
| #   - sys-apps/net-tools (`netstat`)                                           # | ||||
| #   - sys-apps/util-linux (`getopt`)                                           # | ||||
| #                                                                              # | ||||
| ################################################################################ | ||||
|  | @ -36,7 +36,7 @@ | |||
| MY_IP="94.199.214.20" | ||||
| 
 | ||||
| # After this point, no editing is required. | ||||
| start=$(date +%s) | ||||
| start="$(date +%s)" | ||||
| 
 | ||||
| # Dependencies of this script. Simple array with the following structure: | ||||
| # (command package [...]) | ||||
|  | @ -51,8 +51,8 @@ dependencies=( | |||
| 	"tr" "sys-apps/coreutils" | ||||
| 	"uniq" "sys-apps/coreutils" | ||||
| 	"grep" "sys-apps/grep" | ||||
| 	"ss" "sys-apps/iproute2" | ||||
| 	"sponge" "sys-apps/moreutils" | ||||
| 	"netstat" "sys-apps/net-tools" | ||||
| 	"getopt" "sys-apps/util-linux" | ||||
| ) | ||||
| 
 | ||||
|  | @ -83,8 +83,8 @@ function is_installed() { | |||
| } | ||||
| 
 | ||||
| function print_missing_dependency() { | ||||
| 	local command="$1" | ||||
| 	local package="$2" | ||||
| 	local command="${1}" | ||||
| 	local package="${2}" | ||||
| 
 | ||||
| 	echo "${red}Command ${bold}${command}${reset}${red} not found.${reset} Please install package ${blue}${package}${reset}." >&2 | ||||
| } | ||||
|  | @ -102,7 +102,7 @@ function check_dependencies() { | |||
| 		package="${dependencies[$i + 1]}" | ||||
| 		is_installed "${command}" "${package}" | ||||
| 		res=$? | ||||
| 		if [[ $res -ne 0 ]] ; then | ||||
| 		if [[ ${res} -ne 0 ]]; then | ||||
| 			print_missing_dependency "${command}" "${package}" | ||||
| 			all_installed=1 | ||||
| 		fi | ||||
|  | @ -174,11 +174,11 @@ function exec_as_root() { | |||
| 
 | ||||
| function filter() { | ||||
| 	# list of current connections | ||||
| 	file="$1" | ||||
| 	file="${1}" | ||||
| 	# subnet extension, e.g. ".0.0" | ||||
| 	ext="$2" | ||||
| 	ext="${2}" | ||||
| 	# subnet suffix, e.g. "/16" | ||||
| 	suffix="$3" | ||||
| 	suffix="${3}" | ||||
| 	rm -f "${filtered}" | ||||
| 	touch "${filtered}" | ||||
| 
 | ||||
|  | @ -206,14 +206,14 @@ function parse_command_line_args() { | |||
| 	unset TEMP | ||||
| 
 | ||||
| 	while true; do | ||||
| 		case "$1" in | ||||
| 		case "${1}" in | ||||
| 		'-a' | '--auto') | ||||
| 				case "$2" in | ||||
| 			case "${2}" in | ||||
| 			'') | ||||
| 				autopilot=1 | ||||
| 				;; | ||||
| 			*[!0-9]*) | ||||
| 						echo "Invalid argument for parameter 'auto': '$2'. Invoke with --help for help." >&2 | ||||
| 				echo "Invalid argument for parameter 'auto': '${2}'. Invoke with --help for help." >&2 | ||||
| 				exit 1 | ||||
| 				;; | ||||
| 			*) | ||||
|  | @ -223,15 +223,15 @@ function parse_command_line_args() { | |||
| 			shift | ||||
| 			;; | ||||
| 		'-c' | '--country') | ||||
| 				IFS=',' read -ra bancountries <<< "$2" | ||||
| 				if [[ -z ${bancountries[@]// } ]] ; then | ||||
| 					echo "Invalid argument for parameter 'country': '$2'. Invoke with --help for help." >&2 | ||||
| 			IFS=',' read -ra bancountries <<<"${2}" | ||||
| 			if [[ -z ${bancountries[@]// /} ]]; then | ||||
| 				echo "Invalid argument for parameter 'country': '${2}'. Invoke with --help for help." >&2 | ||||
| 				exit 1 | ||||
| 			fi | ||||
| 			shift | ||||
| 			;; | ||||
| 		'-d' | '--database') | ||||
| 				database="$2" | ||||
| 			database="${2}" | ||||
| 			shift | ||||
| 			;; | ||||
| 		'-e' | '--dependencies') | ||||
|  | @ -239,11 +239,11 @@ function parse_command_line_args() { | |||
| 			exit $? | ||||
| 			;; | ||||
| 		'-j' | '--jail') | ||||
| 				jail="$2" | ||||
| 			jail="${2}" | ||||
| 			shift | ||||
| 			;; | ||||
| 		'-n' | '--netmask') | ||||
| 				case "$2" in | ||||
| 			case "${2}" in | ||||
| 			'1' | '8') | ||||
| 				netmask=8 | ||||
| 				;; | ||||
|  | @ -257,14 +257,14 @@ function parse_command_line_args() { | |||
| 				netmask=32 | ||||
| 				;; | ||||
| 			*) | ||||
| 						echo "Invalid argument for parameter 'netmask': '$2'. Invoke with --help for help." >&2 | ||||
| 				echo "Invalid argument for parameter 'netmask': '${2}'. Invoke with --help for help." >&2 | ||||
| 				exit 1 | ||||
| 				;; | ||||
| 			esac | ||||
| 			shift | ||||
| 			;; | ||||
| 		'-p' | '--port') | ||||
| 				port="$2" | ||||
| 			port="${2}" | ||||
| 			shift | ||||
| 			;; | ||||
| 		'-h' | '--help') | ||||
|  | @ -276,7 +276,7 @@ function parse_command_line_args() { | |||
| 			break | ||||
| 			;; | ||||
| 		*) | ||||
| 				echo "Unknown error on command line argument '$1'. Terminating." >&2 | ||||
| 			echo "Unknown error on command line argument '${1}'. Terminating." >&2 | ||||
| 			exit 1 | ||||
| 			;; | ||||
| 		esac | ||||
|  | @ -301,13 +301,13 @@ function parse_command_line_args() { | |||
| # color to the next happen at different values. | ||||
| ################################################################################ | ||||
| function set_highlight_color() { | ||||
| 	local count=$1 | ||||
| 	local count=${1} | ||||
| 	case "${choice}" in | ||||
| 	"1") | ||||
| 		# /32: 0 <= green < 3 <= yellow < 5 <= red | ||||
| 			if [ $count -ge 5 ] ; then | ||||
| 		if [ ${count} -ge 5 ]; then | ||||
| 			hilite="${red}" | ||||
| 			elif [ $count -ge 3 ] ; then | ||||
| 		elif [ ${count} -ge 3 ]; then | ||||
| 			hilite="${yellow}" | ||||
| 		else | ||||
| 			hilite="${green}" | ||||
|  | @ -315,9 +315,9 @@ function set_highlight_color() { | |||
| 		;; | ||||
| 	"2") | ||||
| 		# /24: 0 <= green < 7 <= yellow < 13 <= red | ||||
| 			if [ $count -ge 13 ] ; then | ||||
| 		if [ ${count} -ge 13 ]; then | ||||
| 			hilite="${red}" | ||||
| 			elif [ $count -ge 7 ] ; then | ||||
| 		elif [ ${count} -ge 7 ]; then | ||||
| 			hilite="${yellow}" | ||||
| 		else | ||||
| 			hilite="${green}" | ||||
|  | @ -325,9 +325,9 @@ function set_highlight_color() { | |||
| 		;; | ||||
| 	"3") | ||||
| 		# /16: 0 <= green < 13 <= yellow < 25 <= red | ||||
| 			if [ $count -ge 25 ] ; then | ||||
| 		if [ ${count} -ge 25 ]; then | ||||
| 			hilite="${red}" | ||||
| 			elif [ $count -ge 13 ] ; then | ||||
| 		elif [ ${count} -ge 13 ]; then | ||||
| 			hilite="${yellow}" | ||||
| 		else | ||||
| 			hilite="${green}" | ||||
|  | @ -335,9 +335,9 @@ function set_highlight_color() { | |||
| 		;; | ||||
| 	"4") | ||||
| 		# /8: 0 <= green < 21 <= yellow < 49 <= red | ||||
| 			if [ $count -ge 49 ] ; then | ||||
| 		if [ ${count} -ge 49 ]; then | ||||
| 			hilite="${red}" | ||||
| 			elif [ $count -ge 21 ] ; then | ||||
| 		elif [ ${count} -ge 21 ]; then | ||||
| 			hilite="${yellow}" | ||||
| 		else | ||||
| 			hilite="${green}" | ||||
|  | @ -376,7 +376,7 @@ function process_file () { | |||
| 		addrwithsuffix="${addronly}${suffix}" | ||||
| 		set_highlight_color "${count}" | ||||
| 		country="$("${curdir}/geoip-lookup.py" -f "${database}" "${addronly}")" | ||||
| 		if [[ autopilot -eq 0 ]] ; then | ||||
| 		if [[ ${autopilot} -eq 0 ]]; then | ||||
| 			echo "Country: '${yellow}${country}${reset}'" | ||||
| 		fi | ||||
| 		echo -n "Address ${bold}$((nline++)) of ${nlines}${reset}: \ | ||||
|  | @ -387,7 +387,7 @@ Found '${blue}${addrwithsuffix}${reset}' ${hilite}${count}${reset} times." | |||
| 			read banaction | ||||
| 		else | ||||
| 			if [[ " ${bancountries[@]} " =~ " ${country} " ]]; then | ||||
| 				if [[ $count -ge $autopilot ]] ; then | ||||
| 				if [[ ${count} -ge ${autopilot} ]]; then | ||||
| 					echo -en "\n${red}Autopilot active. ${reset}" | ||||
| 					banaction=y | ||||
| 				else | ||||
|  | @ -395,7 +395,7 @@ Found '${blue}${addrwithsuffix}${reset}' ${hilite}${count}${reset} times." | |||
| 					return | ||||
| 				fi | ||||
| 			else | ||||
| 				if [[ $count -ge $autopilot ]] ; then | ||||
| 				if [[ ${count} -ge ${autopilot} ]]; then | ||||
| 					echo -en "\n${green}Autopilot active. ${reset}" | ||||
| 					banaction=n | ||||
| 				else | ||||
|  | @ -427,7 +427,7 @@ banlist (country=${yellow}${country}${reset})." | |||
| 
 | ||||
| # Create a temp directory, chdir into it and create the (initially empty) | ||||
| # banlist file. | ||||
| tmpdir=$(mktemp -d) | ||||
| tmpdir="$(mktemp -d)" | ||||
| 
 | ||||
| # Set up all file paths | ||||
| curdir="$(dirname "$0")" | ||||
|  | @ -440,8 +440,6 @@ file24="${tmpdir}/sorted-http-24.txt" | |||
| file32="${tmpdir}/sorted-http-32.txt" | ||||
| # This file will contain the addresses to be banned. | ||||
| banlist="${tmpdir}/banlist.txt" | ||||
| # This file contains the output of the last invocation of whois | ||||
| whoisoutput="${tmpdir}/whois.txt" | ||||
| 
 | ||||
| touch "${banlist}" | ||||
| 
 | ||||
|  | @ -466,11 +464,15 @@ banned="$(exec_as_root fail2ban-client get "${jail}" banip)" | |||
| 
 | ||||
| # Determine the current connections to the desired port; store the raw data in | ||||
| # $fileraw. | ||||
| netstat -nt | grep "${MY_IP}:${port}" | tr -s '[:blank:]' | cut -d' ' -f5 \ | ||||
|   | cut -d: -f1 | sort > "${fileraw}" | ||||
| connections=$(ss -HOn state established "( sport = :${port} )" | tr -s '[:blank:]' | cut -d' ' -f5) | ||||
| 
 | ||||
| # IPv6-mapped-IPv4: [::ffff:192.168.0.1]:443 | ||||
| echo "${connections}" | grep '^\[::ffff:' - | cut -d: -f4 | cut -d] -f1 | grep -v '^$' >"${fileraw}" | ||||
| # Pure IPv4: 192.168.0.1:443 | ||||
| echo "${connections}" | grep -v '^\[' - | cut -d: -f1 | grep -v '^$' >>"${fileraw}" | ||||
| 
 | ||||
| # Group and sort the data into the subnet-specific files. | ||||
| cp "${fileraw}" "${file32}" | ||||
| sort "${fileraw}" >"${file32}" | ||||
| cut -d. -f1-3 "${fileraw}" | sort >"${file24}" | ||||
| cut -d. -f1-2 "${fileraw}" | sort >"${file16}" | ||||
| cut -d. -f1 "${fileraw}" | sort >"${file8}" | ||||
|  | @ -559,6 +561,6 @@ while read -r addrwithsuffix ; do | |||
| 	exec_as_root fail2ban-client set "${jail}" banip "${addrwithsuffix}" | ||||
| done <"${banlist}" | ||||
| 
 | ||||
| end=$(date +%s) | ||||
| end="$(date +%s)" | ||||
| 
 | ||||
| echo "${green}All done in $((end - start)) seconds!${reset}" | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue