|
| 1 | +#!/bin/bash |
| 2 | +# info: add firewall ipset |
| 3 | +# options: NAME [SOURCE] [IPVERSION] [AUTOUPDATE] [FORCE] |
| 4 | +# |
| 5 | +# The function adds new ipset to system firewall |
| 6 | + |
| 7 | +#----------------------------------------------------------# |
| 8 | +# Variable&Function # |
| 9 | +#----------------------------------------------------------# |
| 10 | + |
| 11 | +ip_name=${1} |
| 12 | +data_source=${2} |
| 13 | +ip_version=${3-v4} |
| 14 | +autoupdate=${4-yes} |
| 15 | +force=${5-no} |
| 16 | + |
| 17 | +# Includes |
| 18 | +source $HESTIA/func/main.sh |
| 19 | +source $HESTIA/conf/hestia.conf |
| 20 | + |
| 21 | + |
| 22 | +#----------------------------------------------------------# |
| 23 | +# Verifications # |
| 24 | +#----------------------------------------------------------# |
| 25 | + |
| 26 | +check_args '1' "$#" 'NAME [SOURCE] [IPVERSION] [AUTOUPDATE] [FORCE]' |
| 27 | +is_format_valid 'ip_name' |
| 28 | +is_boolean_format_valid "$autoupdate" 'bool (yes/no)' |
| 29 | +is_boolean_format_valid "$force" 'bool (yes/no)' |
| 30 | +is_system_enabled "$FIREWALL_SYSTEM" 'FIREWALL_SYSTEM' |
| 31 | + |
| 32 | +ipset_hstobject='../../data/firewall/ipset' |
| 33 | + |
| 34 | +IPSET_BIN="$(which ipset)" |
| 35 | +IPSET_PATH="$HESTIA/data/firewall/ipset" |
| 36 | + |
| 37 | +if [ -z "$data_source" ]; then |
| 38 | + if [ ! -f "${IPSET_PATH}.conf" ] || [[ ! $(grep "LISTNAME='$ip_name'" "${IPSET_PATH}.conf") ]]; then |
| 39 | + check_args '2' "$#" 'NAME SOURCE [IPVERSION] [AUTOUPDATE] [FORCE]' |
| 40 | + fi |
| 41 | + |
| 42 | + data_source="$(get_object_value "$ipset_hstobject" 'LISTNAME' "$ip_name" '$SOURCE')" |
| 43 | + ip_version="$(get_object_value "$ipset_hstobject" 'LISTNAME' "$ip_name" '$IP_VERSION')" |
| 44 | +else |
| 45 | + is_object_new "$ipset_hstobject" 'LISTNAME' "$ip_name" |
| 46 | +fi |
| 47 | + |
| 48 | +if [ "$ip_version" != "v4" ] && [ "$ip_version" != "v6" ]; then |
| 49 | + check_result $E_INVALID "invalid ip version, valid: (v4|v6)" |
| 50 | +fi |
| 51 | + |
| 52 | +if ! echo "$data_source" | egrep -q '^(https?|script|file):'; then |
| 53 | + check_result $E_INVALID "invalid ipset source, valid: (http[s]://|script:|file:)" |
| 54 | +fi |
| 55 | + |
| 56 | + |
| 57 | +IPSET_FILE="${ip_name}.${ip_version}" |
| 58 | +IPSET_MIN_SIZE=10 |
| 59 | + |
| 60 | +# Perform verification if read-only mode is enabled |
| 61 | +check_hestia_demo_mode |
| 62 | + |
| 63 | +# Install ipset package if missing |
| 64 | +if [ -z "$IPSET_BIN" ]; then |
| 65 | + apt-get --quiet --yes install ipset > /dev/null |
| 66 | + check_result $? "Installing ipset package" |
| 67 | + |
| 68 | + IPSET_BIN="$(which ipset)" |
| 69 | + check_result $? "ipset binary not found" |
| 70 | +fi |
| 71 | + |
| 72 | + |
| 73 | +#----------------------------------------------------------# |
| 74 | +# Action # |
| 75 | +#----------------------------------------------------------# |
| 76 | + |
| 77 | +mkdir -p "$IPSET_PATH" |
| 78 | + |
| 79 | +# Generate ip lists file if missing or when forced |
| 80 | +if [ ! -f "${IPSET_PATH}/${IPSET_FILE}.iplist" ] || [ "$force" = "yes" ]; then |
| 81 | + |
| 82 | + iplist_tempfile=$(mktemp) |
| 83 | + |
| 84 | + if [[ "$data_source" =~ ^https?:// ]]; then |
| 85 | + |
| 86 | + wget --tries=3 --timeout=15 --read-timeout=15 --waitretry=3 --no-dns-cache --quiet "$data_source" -O "$iplist_tempfile" |
| 87 | + check_result $? "Downloading ip list" |
| 88 | + |
| 89 | + # Advanced: execute script with the same basename for aditional pre-processing |
| 90 | + # ex: |
| 91 | + if [ -x "${IPSET_PATH}/${IPSET_FILE}.sh" ]; then |
| 92 | + setpriv --clear-groups --reuid nobody --regid nogroup -- ${IPSET_PATH}/${IPSET_FILE}.sh "$ip_name" "$iplist_tempfile" |
| 93 | + fi |
| 94 | + |
| 95 | + elif [[ "$data_source" =~ ^script:/ ]]; then |
| 96 | + |
| 97 | + # Generate the ip list file trough a external script |
| 98 | + # ex: compiling a ip list from multiple sources on demand |
| 99 | + |
| 100 | + if [ -x "${data_source#script:}" ]; then |
| 101 | + |
| 102 | + setpriv --clear-groups --reuid nobody --regid nogroup -- ${data_source#script:} "$ip_name" > "$iplist_tempfile" |
| 103 | + check_result $? "Running custom ip list update script" |
| 104 | + |
| 105 | + fi |
| 106 | + |
| 107 | + elif [[ "$data_source" =~ ^file:/ ]]; then |
| 108 | + |
| 109 | + # Use a external ip-list file managed by other apps |
| 110 | + # ex: Using a ip list that is continously updated |
| 111 | + |
| 112 | + [ -f "${data_source#file:}" ] && cp -f "${data_source#file:}" "$iplist_tempfile" |
| 113 | + |
| 114 | + fi |
| 115 | + |
| 116 | + # Validate iplist file size |
| 117 | + iplist_size=$(sed -r -e '/^#|^$/d' "$iplist_tempfile" | wc -l) |
| 118 | + [[ "$iplist_size" -le $IPSET_MIN_SIZE ]] && check_result $E_INVALID "iplist file too small (<${IPSET_MIN_SIZE}), ignoring" |
| 119 | + mv -f "$iplist_tempfile" "${IPSET_PATH}/${IPSET_FILE}.iplist" |
| 120 | + |
| 121 | +fi |
| 122 | + |
| 123 | +# Load ipset in kernel |
| 124 | +inet_ver="inet" |
| 125 | +[ "$ip_version" == "v6" ] && inet_ver="inet6" |
| 126 | + |
| 127 | +$IPSET_BIN create "$ip_name" -exist hash:net family $inet_ver |
| 128 | +$IPSET_BIN create "${ip_name}-tmp" -exist hash:net family $inet_ver |
| 129 | +$IPSET_BIN flush "${ip_name}-tmp" |
| 130 | + |
| 131 | +sed -rn -e '/^#|^$/d' -e "s/^(.*)/add ${ip_name}-tmp \\1/p" "${IPSET_PATH}/${IPSET_FILE}.iplist" | $IPSET_BIN -quiet restore |
| 132 | +check_result $? "Populating ipset table" |
| 133 | + |
| 134 | +$IPSET_BIN swap "${ip_name}-tmp" "${ip_name}" |
| 135 | +$IPSET_BIN --quiet destroy "${ip_name}-tmp" |
| 136 | + |
| 137 | + |
| 138 | +# Generating timestamp |
| 139 | +time_n_date=$(date +'%T %F') |
| 140 | +time=$(echo "$time_n_date" |cut -f 1 -d \ ) |
| 141 | +date=$(echo "$time_n_date" |cut -f 2 -d \ ) |
| 142 | + |
| 143 | +if [ ! -f "${IPSET_PATH}.conf" ] || [ -z "$(get_object_value "$ipset_hstobject" 'LISTNAME' "$ip_name" '$LISTNAME')" ]; then |
| 144 | + |
| 145 | + # Concatenating rule |
| 146 | + str="LISTNAME='$ip_name' IP_VERSION='$ip_version' SOURCE='$data_source'" |
| 147 | + str="$str AUTOUPDATE='$autoupdate' SUSPENDED='no'" |
| 148 | + str="$str TIME='$time' DATE='$date'" |
| 149 | + echo "$str" >> $HESTIA/data/firewall/ipset.conf |
| 150 | + |
| 151 | +elif [ "$force" = "yes" ]; then |
| 152 | + |
| 153 | + # update iplist last regen time |
| 154 | + update_object_value "$ipset_hstobject" 'LISTNAME' "$ip_name" '$TIME' "$time" |
| 155 | + update_object_value "$ipset_hstobject" 'LISTNAME' "$ip_name" '$DATE' "$date" |
| 156 | + |
| 157 | +fi |
| 158 | + |
| 159 | +# Changing permissions |
| 160 | +chmod 660 $HESTIA/data/firewall/ipset.conf |
| 161 | +chmod 660 "${IPSET_PATH}/${IPSET_FILE}.iplist" |
| 162 | + |
| 163 | + |
| 164 | +#----------------------------------------------------------# |
| 165 | +# Hestia # |
| 166 | +#----------------------------------------------------------# |
| 167 | + |
| 168 | +# Logging |
| 169 | +log_event "$OK" "$ARGUMENTS" |
| 170 | + |
| 171 | +exit |
0 commit comments