You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					206 lines
				
				7.4 KiB
			
		
		
			
		
	
	
					206 lines
				
				7.4 KiB
			| 
								 
											2 years ago
										 
									 | 
							
								#!/bin/bash
							 | 
						||
| 
								 | 
							
								# info: add firewall ipset
							 | 
						||
| 
								 | 
							
								# options: NAME [SOURCE] [IPVERSION] [AUTOUPDATE] [REFRESH]
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# example: v-add-firewall-ipset country-nl "https://raw.githubusercontent.com/ipverse/rir-ip/master/country/nl/ipv4-aggregated.txt"
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# This function adds new ipset to system firewall
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#----------------------------------------------------------#
							 | 
						||
| 
								 | 
							
								#                Variables & Functions                     #
							 | 
						||
| 
								 | 
							
								#----------------------------------------------------------#
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ip_name=${1}
							 | 
						||
| 
								 | 
							
								data_source=${2}
							 | 
						||
| 
								 | 
							
								ip_version=${3:-v4}
							 | 
						||
| 
								 | 
							
								autoupdate=${4:-yes}
							 | 
						||
| 
								 | 
							
								refresh=${5:-no}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Includes
							 | 
						||
| 
								 | 
							
								# shellcheck source=/etc/hestiacp/hestia.conf
							 | 
						||
| 
								 | 
							
								source /etc/hestiacp/hestia.conf
							 | 
						||
| 
								 | 
							
								# shellcheck source=/usr/local/hestia/func/main.sh
							 | 
						||
| 
								 | 
							
								source $HESTIA/func/main.sh
							 | 
						||
| 
								 | 
							
								# load config file
							 | 
						||
| 
								 | 
							
								source_conf "$HESTIA/conf/hestia.conf"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#----------------------------------------------------------#
							 | 
						||
| 
								 | 
							
								#                    Verifications                         #
							 | 
						||
| 
								 | 
							
								#----------------------------------------------------------#
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								check_args '1' "$#" 'NAME [SOURCE] [IPVERSION] [AUTOUPDATE] [FORCE]'
							 | 
						||
| 
								 | 
							
								is_format_valid 'ip_name'
							 | 
						||
| 
								 | 
							
								is_boolean_format_valid "$autoupdate" 'Automatically update IP list (yes/no)'
							 | 
						||
| 
								 | 
							
								is_boolean_format_valid "$refresh" 'Refresh IP list (yes/no)'
							 | 
						||
| 
								 | 
							
								is_system_enabled "$FIREWALL_SYSTEM" 'FIREWALL_SYSTEM'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Perform verification if read-only mode is enabled
							 | 
						||
| 
								 | 
							
								check_hestia_demo_mode
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Define variables for ipset configuration
							 | 
						||
| 
								 | 
							
								ipset_hstobject='../../data/firewall/ipset'
							 | 
						||
| 
								 | 
							
								IPSET_BIN="$(command -v ipset)"
							 | 
						||
| 
								 | 
							
								IPSET_PATH="$HESTIA/data/firewall/ipset"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Ensure ipset is installed
							 | 
						||
| 
								 | 
							
								if [ -z "$IPSET_BIN" ]; then
							 | 
						||
| 
								 | 
							
									if [ -f '/etc/redhat-release' ]; then
							 | 
						||
| 
								 | 
							
										dnf install -q -y ipset > /dev/null
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										apt-get --quiet --yes install ipset > /dev/null
							 | 
						||
| 
								 | 
							
									fi
							 | 
						||
| 
								 | 
							
									check_result $? "Installing IPset package"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									IPSET_BIN="$(which ipset)"
							 | 
						||
| 
								 | 
							
									check_result $? "IPset binary not found"
							 | 
						||
| 
								 | 
							
								fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Ensure ipset configuration path and master file exist before attempting to parse
							 | 
						||
| 
								 | 
							
								mkdir -p "$IPSET_PATH"
							 | 
						||
| 
								 | 
							
								if [ ! -f "$HESTIA/data/firewall/ipset.conf" ]; then
							 | 
						||
| 
								 | 
							
									touch $HESTIA/data/firewall/ipset.conf
							 | 
						||
| 
								 | 
							
								fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if [ -z "$data_source" ]; then
							 | 
						||
| 
								 | 
							
									if [ ! -f "${IPSET_PATH}.conf" ] || [[ ! $(grep "LISTNAME='$ip_name'" "${IPSET_PATH}.conf") ]]; then
							 | 
						||
| 
								 | 
							
										check_args '2' "$#" 'NAME SOURCE [IPVERSION] [AUTOUPDATE] [FORCE]'
							 | 
						||
| 
								 | 
							
									fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									data_source="$(get_object_value "$ipset_hstobject" 'LISTNAME' "$ip_name" '$SOURCE')"
							 | 
						||
| 
								 | 
							
									ip_version="$(get_object_value "$ipset_hstobject" 'LISTNAME' "$ip_name" '$IP_VERSION')"
							 | 
						||
| 
								 | 
							
								else
							 | 
						||
| 
								 | 
							
									is_object_new "$ipset_hstobject" 'LISTNAME' "$ip_name"
							 | 
						||
| 
								 | 
							
								fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if [ "$ip_version" != "v4" ] && [ "$ip_version" != "v6" ]; then
							 | 
						||
| 
								 | 
							
									check_result "$E_INVALID" "invalid ip version, valid: (v4|v6)"
							 | 
						||
| 
								 | 
							
								fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if ! echo "$data_source" | egrep -q '^(https?|script|file):'; then
							 | 
						||
| 
								 | 
							
									check_result "$E_INVALID" "invalid ipset source, valid: (http[s]://|script:|file:)"
							 | 
						||
| 
								 | 
							
								fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								IPSET_FILE="${ip_name}.${ip_version}"
							 | 
						||
| 
								 | 
							
								IPSET_MIN_SIZE=10
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#----------------------------------------------------------#
							 | 
						||
| 
								 | 
							
								#                       Action                             #
							 | 
						||
| 
								 | 
							
								#----------------------------------------------------------#
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Generate ip lists file if missing or required refresh
							 | 
						||
| 
								 | 
							
								if [ ! -f "${IPSET_PATH}/${IPSET_FILE}.iplist" ] || [ "$refresh" = "yes" ]; then
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									iplist_tempfile=$(mktemp)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if [[ "$data_source" =~ ^https?:// ]]; then
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										wget --tries=3 --timeout=15 --read-timeout=15 --waitretry=3 --no-dns-cache --quiet "$data_source" -O "$iplist_tempfile"
							 | 
						||
| 
								 | 
							
										check_result $? "Downloading ip list"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										# Advanced: execute script with the same basename for aditional pre-processing
							 | 
						||
| 
								 | 
							
										# ex:
							 | 
						||
| 
								 | 
							
										if [ -x "${IPSET_PATH}/${IPSET_FILE}.sh" ]; then
							 | 
						||
| 
								 | 
							
											if [ -e '/etc/redhat-release' ]; then
							 | 
						||
| 
								 | 
							
												preprocess_output="$(cat "$iplist_tempfile" | setpriv --clear-groups --reuid nobody --regid nobody -- ${IPSET_PATH}/${IPSET_FILE}.sh "$ip_name" "$iplist_tempfile")"
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
												preprocess_output="$(cat "$iplist_tempfile" | setpriv --clear-groups --reuid nobody --regid nogroup -- ${IPSET_PATH}/${IPSET_FILE}.sh "$ip_name" "$iplist_tempfile")"
							 | 
						||
| 
								 | 
							
											fi
							 | 
						||
| 
								 | 
							
											check_result $? "Preprocessing script failed (${IPSET_FILE}.sh)"
							 | 
						||
| 
								 | 
							
											[[ "$preprocess_output" ]] && echo "$preprocess_output" > "$iplist_tempfile"
							 | 
						||
| 
								 | 
							
										fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									elif [[ "$data_source" =~ ^script:/ ]]; then
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										# Generate the ip list file trough a external script
							 | 
						||
| 
								 | 
							
										# ex: compiling a ip list from multiple sources on demand
							 | 
						||
| 
								 | 
							
										if [ -x "${data_source#script:}" ]; then
							 | 
						||
| 
								 | 
							
											if [ -e '/etc/redhat-release' ]; then
							 | 
						||
| 
								 | 
							
												setpriv --clear-groups --reuid nobody --regid nobody -- ${data_source#script:} "$ip_name" > "$iplist_tempfile"
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
												setpriv --clear-groups --reuid nobody --regid nogroup -- ${data_source#script:} "$ip_name" > "$iplist_tempfile"
							 | 
						||
| 
								 | 
							
											fi
							 | 
						||
| 
								 | 
							
											check_result $? "Running custom ip list update script"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									elif [[ "$data_source" =~ ^file:/ ]]; then
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										# Use a external ip-list file managed by other apps
							 | 
						||
| 
								 | 
							
										# ex: Using a ip list that is continuously updated
							 | 
						||
| 
								 | 
							
										[ -f "${data_source#file:}" ] && cp -f "${data_source#file:}" "$iplist_tempfile"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									# Cleanup ip list
							 | 
						||
| 
								 | 
							
									sed -r -i -e 's/[;#].*$//' -e 's/[ \t]*$//' -e '/^$/d' "$iplist_tempfile"
							 | 
						||
| 
								 | 
							
									if [[ $ip_version == 'v4' ]]; then
							 | 
						||
| 
								 | 
							
										sed -i -r -n -e '/^((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])/p' "$iplist_tempfile"
							 | 
						||
| 
								 | 
							
									elif [[ $ip_version == 'v6' ]]; then
							 | 
						||
| 
								 | 
							
										sed -i -r -n -e '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}/p' "$iplist_tempfile"
							 | 
						||
| 
								 | 
							
									fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									# Validate iplist file size
							 | 
						||
| 
								 | 
							
									iplist_size=$(sed -r -e '/^#|^$/d' "$iplist_tempfile" | wc -l)
							 | 
						||
| 
								 | 
							
									[[ "$iplist_size" -le "$IPSET_MIN_SIZE" ]] && check_result "$E_INVALID" "IP list file too small (<${IPSET_MIN_SIZE}), ignoring"
							 | 
						||
| 
								 | 
							
									mv -f "$iplist_tempfile" "${IPSET_PATH}/${IPSET_FILE}.iplist"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Load ipset in kernel
							 | 
						||
| 
								 | 
							
								inet_ver="inet"
							 | 
						||
| 
								 | 
							
								[ "$ip_version" == "v6" ] && inet_ver="inet6"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								$IPSET_BIN -quiet create -exist "$ip_name" hash:net family $inet_ver
							 | 
						||
| 
								 | 
							
								$IPSET_BIN -quiet destroy "${ip_name}-tmp"
							 | 
						||
| 
								 | 
							
								$IPSET_BIN create "${ip_name}-tmp" -exist hash:net family $inet_ver maxelem 1048576
							 | 
						||
| 
								 | 
							
								$IPSET_BIN flush "${ip_name}-tmp"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								sed -rn -e '/^#|^$/d' -e "s/^(.*)/add ${ip_name}-tmp \\1/p" "${IPSET_PATH}/${IPSET_FILE}.iplist" | $IPSET_BIN -quiet restore
							 | 
						||
| 
								 | 
							
								check_result $? "Populating ipset table"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								$IPSET_BIN swap "${ip_name}-tmp" "${ip_name}"
							 | 
						||
| 
								 | 
							
								$IPSET_BIN -quiet destroy "${ip_name}-tmp"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Generating timestamp
							 | 
						||
| 
								 | 
							
								time_n_date=$(date +'%T %F')
							 | 
						||
| 
								 | 
							
								time=$(echo "$time_n_date" | cut -f 1 -d \ )
							 | 
						||
| 
								 | 
							
								date=$(echo "$time_n_date" | cut -f 2 -d \ )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if [ ! -f "${IPSET_PATH}.conf" ] || [ -z "$(get_object_value "$ipset_hstobject" 'LISTNAME' "$ip_name" '$LISTNAME')" ]; then
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									# Concatenating rule
							 | 
						||
| 
								 | 
							
									str="LISTNAME='$ip_name' IP_VERSION='$ip_version' SOURCE='$data_source'"
							 | 
						||
| 
								 | 
							
									str="$str AUTOUPDATE='$autoupdate' SUSPENDED='no'"
							 | 
						||
| 
								 | 
							
									str="$str TIME='$time' DATE='$date'"
							 | 
						||
| 
								 | 
							
									echo "$str" >> $HESTIA/data/firewall/ipset.conf
							 | 
						||
| 
								 | 
							
									log_type="added"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								elif [ "$refresh" = "yes" ]; then
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									# Update iplist last regen time
							 | 
						||
| 
								 | 
							
									update_object_value "$ipset_hstobject" 'LISTNAME' "$ip_name" '$TIME' "$time"
							 | 
						||
| 
								 | 
							
									update_object_value "$ipset_hstobject" 'LISTNAME' "$ip_name" '$DATE' "$date"
							 | 
						||
| 
								 | 
							
									log_type="refreshed"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Changing permissions
							 | 
						||
| 
								 | 
							
								chmod 660 $HESTIA/data/firewall/ipset.conf
							 | 
						||
| 
								 | 
							
								chmod 660 "${IPSET_PATH}/${IPSET_FILE}.iplist"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Install ipset daily cron updater
							 | 
						||
| 
								 | 
							
								if ! grep --silent --no-messages "v-update-firewall-ipset" $HESTIA/data/queue/daily.pipe; then
							 | 
						||
| 
								 | 
							
									cmd="$BIN/v-update-firewall-ipset yes"
							 | 
						||
| 
								 | 
							
									echo "$cmd" >> $HESTIA/data/queue/daily.pipe
							 | 
						||
| 
								 | 
							
								fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#----------------------------------------------------------#
							 | 
						||
| 
								 | 
							
								#                       Hestia                             #
							 | 
						||
| 
								 | 
							
								#----------------------------------------------------------#
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Logging
							 | 
						||
| 
								 | 
							
								$BIN/v-log-action "system" "Info" "Firewall" "IPset IP list ${log_type:-loaded} (Name: $ip_name, IP version: $ip_version, Autoupdate: $autoupdate)."
							 | 
						||
| 
								 | 
							
								log_event "$OK" "$ARGUMENTS"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								exit
							 |