Skip to content

Commit e9ee6da

Browse files
committed
[cli] add support for using linux ipset lists
1 parent 540c259 commit e9ee6da

File tree

4 files changed

+407
-0
lines changed

4 files changed

+407
-0
lines changed

bin/v-add-firewall-ipset

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
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

bin/v-delete-firewall-ipset

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/bin/bash
2+
# info: delete firewall ipset
3+
# options: NAME
4+
#
5+
# The function removes ipset from system and from hestia
6+
7+
8+
#----------------------------------------------------------#
9+
# Variable&Function #
10+
#----------------------------------------------------------#
11+
12+
ip_name=${1}
13+
14+
# Includes
15+
source $HESTIA/func/main.sh
16+
source $HESTIA/conf/hestia.conf
17+
18+
19+
#----------------------------------------------------------#
20+
# Verifications #
21+
#----------------------------------------------------------#
22+
23+
ipset_hstobject='../../data/firewall/ipset'
24+
25+
check_args '1' "$#" 'NAME'
26+
is_format_valid 'ip_name'
27+
is_system_enabled "$FIREWALL_SYSTEM" 'FIREWALL_SYSTEM'
28+
is_object_valid "$ipset_hstobject" 'LISTNAME' "$ip_name"
29+
30+
ip_version="$(get_object_value "$ipset_hstobject" 'LISTNAME' "$ip_name" '$IP_VERSION')"
31+
32+
IPSET_BIN="$(which ipset)"
33+
IPSET_PATH="$HESTIA/data/firewall/ipset"
34+
IPSET_FILE="${ip_name}.${ip_version}"
35+
36+
# Perform verification if read-only mode is enabled
37+
check_hestia_demo_mode
38+
39+
# Install ipset package if missing
40+
if [ -z "$IPSET_BIN" ]; then
41+
apt-get --quiet --yes install ipset > /dev/null
42+
check_result $? "Installing ipset package"
43+
44+
IPSET_BIN="$(which ipset)"
45+
check_result $? "ipset binary not found"
46+
fi
47+
48+
49+
#----------------------------------------------------------#
50+
# Action #
51+
#----------------------------------------------------------#
52+
53+
if $IPSET_BIN --quiet list "${ip_name}-tmp"; then
54+
$IPSET_BIN --quiet destroy "${ip_name}-tmp"
55+
fi
56+
57+
if $IPSET_BIN --quiet list "${ip_name}"; then
58+
$IPSET_BIN --quiet destroy "${ip_name}"
59+
check_result $? "ipset ${ip_name} still used by iptables. Cannot remove"
60+
fi
61+
62+
sed -i "/LISTNAME='$ip_name'/d" "${IPSET_PATH}.conf"
63+
rm -f "${IPSET_PATH}/${IPSET_FILE}.iplist"
64+
65+
#----------------------------------------------------------#
66+
# Hestia #
67+
#----------------------------------------------------------#
68+
69+
# Logging
70+
log_event "$OK" "$ARGUMENTS"
71+
72+
exit

bin/v-list-firewall-ipset

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/bin/bash
2+
# info: List firewall ipset
3+
# options: [FORMAT]
4+
#
5+
# The function prints defined ipset lists
6+
7+
8+
#----------------------------------------------------------#
9+
# Variable&Function #
10+
#----------------------------------------------------------#
11+
12+
# Argument definition
13+
format=${1-shell}
14+
15+
# Includes
16+
source $HESTIA/func/main.sh
17+
source $HESTIA/conf/hestia.conf
18+
19+
20+
#----------------------------------------------------------#
21+
# Verifications #
22+
#----------------------------------------------------------#
23+
24+
is_system_enabled "$FIREWALL_SYSTEM" 'FIREWALL_SYSTEM'
25+
26+
27+
#----------------------------------------------------------#
28+
# Action #
29+
#----------------------------------------------------------#
30+
31+
# JSON list function
32+
json_list() {
33+
IFS=$'\n'
34+
i=1
35+
objects=$(grep LISTNAME $HESTIA/data/firewall/ipset.conf |wc -l)
36+
echo "{"
37+
while read str; do
38+
[[ -z "$str" ]] && continue;
39+
parse_object_kv_list "$str"
40+
echo -n ' "'$LISTNAME'": {
41+
"IP_VERSION": "'$IP_VERSION'",
42+
"AUTOUPDATE": "'$AUTOUPDATE'",
43+
"SUSPENDED": "'$SUSPENDED'",
44+
"SOURCE": "'$SOURCE'",
45+
"TIME": "'$TIME'",
46+
"DATE": "'$DATE'"
47+
}'
48+
[[ "$i" -lt "$objects" ]] && echo ',' || echo
49+
((i++))
50+
done < <(cat $HESTIA/data/firewall/ipset.conf)
51+
echo '}'
52+
}
53+
54+
# SHELL list function
55+
shell_list() {
56+
IFS=$'\n'
57+
echo "LISTNAME^IP_VERSION^AUTOUPDATE^SUSPENDED^SOURCE^TIME^DATE"
58+
echo "----^------^-----^----^--^----^----"
59+
while read str; do
60+
[[ -z "$str" ]] && continue;
61+
parse_object_kv_list "$str"
62+
echo "$LISTNAME^$IP_VERSION^$AUTOUPDATE^$SUSPENDED^$SOURCE^$TIME^$DATE"
63+
done < <(cat $HESTIA/data/firewall/ipset.conf)
64+
}
65+
66+
# PLAIN list function
67+
plain_list() {
68+
IFS=$'\n'
69+
while read str; do
70+
[[ -z "$str" ]] && continue;
71+
parse_object_kv_list "$str"
72+
echo -ne "$LISTNAME\t$IP_VERSION\t$AUTOUPDATE\t$SUSPENDED\t$SOURCE\t"
73+
echo -e "$TIME\t$DATE"
74+
done < <(cat $HESTIA/data/firewall/ipset.conf)
75+
}
76+
77+
# CSV list function
78+
csv_list() {
79+
IFS=$'\n'
80+
echo "LISTNAME,IP_VERSION,AUTOUPDATE,SUSPENDED,SOURCE,SUSPENDED,TIME,DATE"
81+
while read str; do
82+
[[ -z "$str" ]] && continue;
83+
parse_object_kv_list "$str"
84+
echo -n "$LISTNAME,$IP_VERSION,$AUTOUPDATE,$SUSPENDED,\"$SOURCE\","
85+
echo "$TIME,$DATE"
86+
done < <(cat $HESTIA/data/firewall/ipset.conf)
87+
}
88+
89+
# Listing data
90+
case $format in
91+
json) json_list ;;
92+
plain) plain_list ;;
93+
csv) csv_list ;;
94+
shell) shell_list |column -t -s '^' ;;
95+
esac
96+
97+
98+
#----------------------------------------------------------#
99+
# Hestia #
100+
#----------------------------------------------------------#
101+
102+
exit

0 commit comments

Comments
 (0)