update ipset to 7.17

This commit is contained in:
xinghe 2023-01-31 06:18:55 +00:00
parent 7e3606638a
commit 356a5de895
8 changed files with 423 additions and 292 deletions

View File

@ -1,93 +0,0 @@
From be7f6099feb7b5d34715b06f9308877cdcdc404a Mon Sep 17 00:00:00 2001
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Mon, 28 Feb 2022 19:52:57 +0100
Subject: Fix IPv6 sets nftables translation
The parser assumes the set is an IPv4 ipset because IPSET_OPT_FAMILY is
not set.
# ipset-translate restore < ./ipset-mwan3_set_connected_ipv6.dump
add table inet global
add set inet global mwan3_connected_v6 { type ipv6_addr; flags interval; }
flush set inet global mwan3_connected_v6
ipset v7.15: Error in line 4: Syntax error: '64' is out of range 0-32
Remove ipset_xlate_type_get(), call ipset_xlate_set_get() instead to
obtain the set type and family.
Reported-by: Florian Eckert <fe@dev.tdt.de>
Fixes: 325af556cd3a ("add ipset to nftables translation infrastructure")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Conflict: NA
Reference: http://git.netfilter.org/ipset/commit/?id=be7f6099feb7b5d34715b06f9308877cdcdc404a
---
lib/ipset.c | 24 ++++++++++--------------
tests/xlate/xlate.t | 2 ++
tests/xlate/xlate.t.nft | 2 ++
3 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/lib/ipset.c b/lib/ipset.c
index 73e67db..50f86ae 100644
--- a/lib/ipset.c
+++ b/lib/ipset.c
@@ -949,18 +949,6 @@ ipset_xlate_set_get(struct ipset *ipset, const char *name)
return NULL;
}
-static const struct ipset_type *ipset_xlate_type_get(struct ipset *ipset,
- const char *name)
-{
- const struct ipset_xlate_set *set;
-
- set = ipset_xlate_set_get(ipset, name);
- if (!set)
- return NULL;
-
- return set->type;
-}
-
static int
ipset_parser(struct ipset *ipset, int oargc, char *oargv[])
{
@@ -1282,8 +1270,16 @@ ipset_parser(struct ipset *ipset, int oargc, char *oargv[])
if (!ipset->xlate) {
type = ipset_type_get(session, cmd);
} else {
- type = ipset_xlate_type_get(ipset, arg0);
- ipset_session_data_set(session, IPSET_OPT_TYPE, type);
+ const struct ipset_xlate_set *xlate_set;
+
+ xlate_set = ipset_xlate_set_get(ipset, arg0);
+ if (xlate_set) {
+ ipset_session_data_set(session, IPSET_OPT_TYPE,
+ xlate_set->type);
+ ipset_session_data_set(session, IPSET_OPT_FAMILY,
+ &xlate_set->family);
+ type = xlate_set->type;
+ }
}
if (type == NULL)
return ipset->standard_error(ipset, p);
diff --git a/tests/xlate/xlate.t b/tests/xlate/xlate.t
index b1e7d28..f09cb20 100644
--- a/tests/xlate/xlate.t
+++ b/tests/xlate/xlate.t
@@ -53,3 +53,5 @@ create bp1 bitmap:port range 1-1024
add bp1 22
create bim1 bitmap:ip,mac range 1.1.1.0/24
add bim1 1.1.1.1,aa:bb:cc:dd:ee:ff
+create hn6 hash:net family inet6
+add hn6 fe80::/64
diff --git a/tests/xlate/xlate.t.nft b/tests/xlate/xlate.t.nft
index 96eba3b..0152a30 100644
--- a/tests/xlate/xlate.t.nft
+++ b/tests/xlate/xlate.t.nft
@@ -54,3 +54,5 @@ add set inet global bp1 { type inet_service; }
add element inet global bp1 { 22 }
add set inet global bim1 { type ipv4_addr . ether_addr; }
add element inet global bim1 { 1.1.1.1 . aa:bb:cc:dd:ee:ff }
+add set inet global hn6 { type ipv6_addr; flags interval; }
+add element inet global hn6 { fe80::/64 }
--
cgit v1.2.3

View File

@ -0,0 +1,44 @@
From f9a5f712132273139473cb322c3155375a1d1836 Mon Sep 17 00:00:00 2001
From: Gavrilov Ilia <Ilia.Gavrilov@infotecs.ru>
Date: Sat, 28 Jan 2023 19:09:52 +0100
Subject: [PATCH] netfilter: ipset: Fix overflow before widen in the
bitmap_ip_create() function.
When first_ip is 0, last_ip is 0xFFFFFFFF, and netmask is 31, the value of
an arithmetic expression 2 << (netmask - mask_bits - 1) is subject
to overflow due to a failure casting operands to a larger data type
before performing the arithmetic.
Note that it's harmless since the value will be checked at the next step.
Found by InfoTeCS on behalf of Linux Verification Center
(linuxtesting.org) with SVACE.
Fixes: b9fed748185a ("netfilter: ipset: Check and reject crazy /0 input parameters")
Signed-off-by: Ilia.Gavrilov <Ilia.Gavrilov@infotecs.ru>
Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
Conflict: NA
Reference: http://git.netfilter.org/ipset/commit/?id=f9a5f712132273139473cb322c3155375a1d1836
---
kernel/net/netfilter/ipset/ip_set_bitmap_ip.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/net/netfilter/ipset/ip_set_bitmap_ip.c b/kernel/net/netfilter/ipset/ip_set_bitmap_ip.c
index c488663..f37169c 100644
--- a/kernel/net/netfilter/ipset/ip_set_bitmap_ip.c
+++ b/kernel/net/netfilter/ipset/ip_set_bitmap_ip.c
@@ -312,8 +312,8 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
return -IPSET_ERR_BITMAP_RANGE;
pr_debug("mask_bits %u, netmask %u\n", mask_bits, netmask);
- hosts = 2 << (32 - netmask - 1);
- elements = 2 << (netmask - mask_bits - 1);
+ hosts = 2U << (32 - netmask - 1);
+ elements = 2UL << (netmask - mask_bits - 1);
}
if (elements > IPSET_BITMAP_MAX_RANGE + 1)
return -IPSET_ERR_BITMAP_RANGE_SIZE;
--
2.27.0

Binary file not shown.

BIN
ipset-7.17.tar.bz2 Normal file

Binary file not shown.

5
ipset-config Normal file
View File

@ -0,0 +1,5 @@
# Save current ipsets on stop.
# Value: yes|no, default: no
# Saves all ipsets to /etc/sysconfig/ipset.d/ if service gets stopped
# (e.g. on system shutdown).
IPSET_SAVE_ON_STOP="no"

View File

@ -9,10 +9,11 @@ RemainAfterExit=yes
ExecStart=/usr/libexec/ipset/ipset.start-stop start ExecStart=/usr/libexec/ipset/ipset.start-stop start
ExecStop=/usr/libexec/ipset/ipset.start-stop stop ExecStop=/usr/libexec/ipset/ipset.start-stop stop
ExecReload=/usr/libexec/ipset/ipset.start-stop reload ExecReload=/usr/libexec/ipset/ipset.start-stop reload
# Save current ipset entries on stop/restart. # Save current ipset entries on stop.
# Value: yes|no, default: no # Value: yes|no, default: no
# Saves all ipsets to /etc/ipset/ipset if ipset gets stopped # Saves all ipsets to /etc/sysconfig/ipset if ipset gets stopped
Environment=IPSET_SAVE_ON_STOP=no IPSET_SAVE_ON_RESTART=no Environment=IPSET_SAVE_ON_STOP=no
EnvironmentFile=-/etc/sysconfig/ipset-config
[Install] [Install]
WantedBy=basic.target WantedBy=basic.target

View File

@ -1,16 +1,17 @@
Name: ipset Name: ipset
Version: 7.15 Version: 7.17
Release: 2 Release: 1
Summary: Manage Linux IP sets Summary: Manage Linux IP sets
License: GPLv2 License: GPLv2
URL: http://ipset.netfilter.org/ URL: http://ipset.netfilter.org/
Source0: http://ipset.netfilter.org/%{name}-%{version}.tar.bz2 Source0: http://ipset.netfilter.org/%{name}-%{version}.tar.bz2
Source1: ipset.service Source1: ipset.service
Source2: ipset.start-stop Source2: ipset.start-stop
Source3: ipset-config
Patch0: backport-Fix-IPv6-sets-nftables-translation.patch Patch0: backport-netfilter-ipset-Fix-overflow-before-widen-in-the-bit.patch
BuildRequires: libmnl-devel automake autoconf libtool libtool-ltdl-devel systemd BuildRequires: libmnl-devel automake autoconf libtool libtool-ltdl-devel systemd make
Requires: ipset-libs = %{version}-%{release} iptables-services Requires: ipset-libs = %{version}-%{release} iptables-services
Requires(post): systemd Requires(post): systemd
Requires(preun): systemd Requires(preun): systemd
@ -71,12 +72,27 @@ install -c -m 644 %{SOURCE1} %{buildroot}/%{_unitdir}
install -d -m 755 %{buildroot}%{_libexecdir}/%{name} install -d -m 755 %{buildroot}%{_libexecdir}/%{name}
install -c -m 755 %{SOURCE2} %{buildroot}%{_libexecdir}/%{name} install -c -m 755 %{SOURCE2} %{buildroot}%{_libexecdir}/%{name}
install -d -m 755 %{buildroot}%{_sysconfdir}/sysconfig
install -c -m 600 %{SOURCE3} %{buildroot}%{_sysconfdir}/sysconfig/%{name}-config
install -d -m 755 %{buildroot}%{_sysconfdir}/%{name} install -d -m 755 %{buildroot}%{_sysconfdir}/%{name}
%ldconfig_scriptlets libs %ldconfig_scriptlets libs
%post %post
%systemd_post %{name}.service %systemd_post %{name}.service
if [[ -f /etc/ipset/ipset ]] && [[ ! -f /etc/sysconfig/ipset ]]; then
mv /etc/ipset/ipset /etc/sysconfig/ipset
ln -s /etc/sysconfig/ipset /etc/ipset/ipset
echo "Warning: ipset save location has moved to /etc/sysconfig"
fi
[[ -f /etc/sysconfig/iptables-config ]] && . /etc/sysconfig/iptables-config
[[ -f /etc/sysconfig/ip6tables-config ]] && . /etc/sysconfig/ip6tables-config
if [[ ${IPTABLES_SAVE_ON_STOP} == yes ]] || \
[[ ${IP6TABLES_SAVE_ON_STOP} == yes ]]; then
echo "Warning: ipset no longer saves automatically when iptables does"
echo " must enable explicitly in /etc/sysconfig/ipset-config"
fi
%preun %preun
if [[ $1 -eq 0 && -n $(lsmod | grep "^xt_set ") ]]; then if [[ $1 -eq 0 && -n $(lsmod | grep "^xt_set ") ]]; then
@ -97,6 +113,8 @@ fi
%{_unitdir}/ipset.service %{_unitdir}/ipset.service
%{_libexecdir}/ipset/ipset.start-stop %{_libexecdir}/ipset/ipset.start-stop
%{_sysconfdir}/%{name} %{_sysconfdir}/%{name}
%config(noreplace) %attr(0600,root,root) %{_sysconfdir}/sysconfig/ipset-config
%ghost %config(noreplace) %attr(0600,root,root) %{_sysconfdir}/sysconfig/ipset
%files libs %files libs
%defattr(-,root,root) %defattr(-,root,root)
@ -116,6 +134,12 @@ fi
%{_mandir}/man3/libipset.3.* %{_mandir}/man3/libipset.3.*
%changelog %changelog
* Wed Feb 01 2023 xinghe <xinghe2@h-partners.com> - 7.17-1
- Type:requirements
- ID:NA
- SUG:NA
- DESC:update ipset to 7.17
* Thu Oct 20 2022 xinghe <xinghe2@h-partners.com> - 7.15-2 * Thu Oct 20 2022 xinghe <xinghe2@h-partners.com> - 7.15-2
- Type:bugfix - Type:bugfix
- ID:NA - ID:NA

View File

@ -1,209 +1,359 @@
#!/bin/bash #!/bin/sh
# #
# ipset Start and stop ipset firewall sets # ipset Start and stop ipset firewall sets
# #
# config: /etc/ipset/ipset # config: /etc/sysconfig/ipset-config
#
IPSET_BIN=/usr/sbin/ipset
IPSET=ipset IPSET_CONFIG=/etc/sysconfig/ipset-config
IPSET_BIN=/usr/sbin/${IPSET} IPSET_DATA_COMPAT=/etc/sysconfig/ipset
IPSET_DATA=/etc/${IPSET}/${IPSET} IPSET_DATA_COMPAT_BACKUP=${IPSET_DATA_COMPAT}.save
IPSET_DATA_DIR=/etc/sysconfig/ipset.d
IPTABLES_CONFIG=/etc/sysconfig/iptables-config IPSET_DATA_DIR_BACKUP=${IPSET_DATA_DIR}.save
IP6TABLES_CONFIG=${IPTABLES_CONFIG/iptables/ip6tables} IPSET_DATA_SAVED_FLAG=${IPSET_DATA_DIR}/.saved
IPSET_LOCK=/run/ipset.lock
TMP_FIFO=/tmp/${IPSET}.$$ IPSET_RUN=/run/ipset.run
CLEAN_FILES=""
if [[ ! -x ${IPSET_BIN} ]]; then
echo "${IPSET_BIN} does not exist." trap "rm -rf \${CLEAN_FILES}" EXIT
exit 5
fi info() {
echo "ipset: ${*}" >&2
CLEAN_FILES=TMP_FIFO
trap "rm -f \$CLEAN_FILES" EXIT
# Default ipset configuration:
[[ -z $IPSET_SAVE_ON_STOP ]] && IPSET_SAVE_ON_STOP=no # Overridden by ip(6)tables IP(6)TABLES_SAVE_ON_STOP
[[ -z $IPSET_SAVE_ON_RESTART ]] && IPSET_SAVE_ON_RESTART=no # Overridden by ip(6)tables IP(6)TABLES_SAVE_ON_RESTART
# Load iptables configuration(s)
[[ -f "$IPTABLES_CONFIG" ]] && . "$IPTABLES_CONFIG"
[[ -f "$IP6TABLES_CONFIG" ]] && . "$IP6TABLES_CONFIG"
# It doesn't make sense to save iptables config and not our config
[[ ${IPTABLES_SAVE_ON_STOP} = yes || ${IP6TABLES_SAVE_ON_STOP} = yes ]] && IPSET_SAVE_ON_STOP=yes
[[ ${IPTABLES_SAVE_ON_RESTART} = yes || ${IP6TABLES_SAVE_ON_RESTART} = yes ]] && IPSET_SAVE_ON_RESTART=yes
check_can_unload() {
# If the xt_set module is loaded and can't be unloaded, then iptables is
# using ipsets, so refuse to stop the service.
if [[ -n $(lsmod | grep "^xt_set ") ]]; then
rmmod xt_set 2>/dev/null
[[ $? -ne 0 ]] && echo Current iptables configuration requires ipsets && return 1
fi
return 0
} }
flush_n_delete() { warn() {
local ret=0 set echo "<4>ipset: ${*}" >&2
# Flush sets
${IPSET_BIN} flush
let ret+=$?
# Delete ipset sets. If we don't do them individually, then none
# will be deleted unless they all can be.
for set in $(${IPSET_BIN} list -name); do
${IPSET_BIN} destroy 2>/dev/null
[[ $? -ne 0 ]] && ret=1
done
return $ret
} }
start_clean() err() {
{ echo "<3>ipset: ${*}" >&2
mkfifo -m go= "${TMP_FIFO}"
[[ $? -ne 0 ]] && return 1
# Get the lists of sets in current(old) config and new config
old_sets="$(${IPSET_BIN} list -name | sort -u)"
new_sets="$(grep ^create "${IPSET_DATA}" | cut -d " " -f 2 | sort -u)"
# List of sets no longer wanted
drop_sets="$( printf "%s\n" "${old_sets}" > "${TMP_FIFO}" &
printf "%s\n" "${new_sets}" | comm -23 "${TMP_FIFO}" -
)"
# Get rid of sets no longer needed
# Unfortunately -! doesn't work for destroy, so we have to do it a command at a time
for dset in $drop_sets; do
ipset destroy $dset 2>/dev/null
# If it won't go - ? in use by iptables, just clear it
[[ $? -ne 0 ]] && ipset flush $dset
done
# Now delete the set members no longer required
${IPSET_BIN} save | grep "^add " | sort >${TMP_FIFO} &
grep "^add " ${IPSET_DATA} | sort | comm -23 ${TMP_FIFO} - | sed -e "s/^add /del /" \
| ${IPSET_BIN} restore -!
# At last we can add the set members we haven't got
ipset restore -! <${IPSET_DATA}
rm ${TMP_FIFO}
return 0
} }
start() { [ -x ${IPSET_BIN} ] || { err "Cannot execute ${IPSET_BIN}"; exit 1; }
# Do not start if there is no config file.
[[ ! -f "$IPSET_DATA" ]] && echo "Loaded with no configuration" && return 0 # Source ipset configuration
# shellcheck source=ipset-config
# We can skip the first bit and do a simple load if [ -f ${IPSET_CONFIG} ] && . ${IPSET_CONFIG}
# there is no current ipset configuration
res=1 set -f
if [[ -n $(${IPSET_BIN} list -name) ]]; then
# The following may fail for some bizarre reason lock() {
start_clean CLEAN_FILES="${CLEAN_FILES} ${IPSET_LOCK}"
res=$? until mkdir ${IPSET_LOCK} 2>/dev/null; do :; done
[[ $res -ne 0 ]] && echo "Some old configuration may remain"
fi
# res -ne 0 => either start_clean failed, or we didn't need to run it
if [[ $res -ne 0 ]]; then
# This is the easy way to start but would leave any old
# entries still configured. Still, better than nothing -
# but fine if we had no config
${IPSET_BIN} restore -! <${IPSET_DATA}
res=$?
fi
if [[ $res -ne 0 ]]; then
return 1
fi
return 0
} }
stop() {
# Nothing to stop if ip_set module is not loaded.
lsmod | grep -q "^ip_set "
[[ $? -ne 0 ]] && return 6
flush_n_delete
[[ $? -ne 0 ]] && echo Warning: Not all sets were flushed/deleted
return 0
}
save() { save() {
# Do not save if ip_set module is not loaded. fail=0
lsmod | grep -q "^ip_set "
[[ $? -ne 0 ]] && return 6 # Make backups of existing configuration first, if any
[ -d ${IPSET_DATA_DIR} ] && mv -Tf ${IPSET_DATA_DIR} ${IPSET_DATA_DIR_BACKUP}
[[ -z $(${IPSET_BIN} list -name) ]] && return 0 [ -f ${IPSET_DATA_COMPAT} ] && mv -Tf ${IPSET_DATA_COMPAT} ${IPSET_DATA_COMPAT_BACKUP}
ret=0 rm -f ${IPSET_DATA_SAVED_FLAG}
TMP_FILE=$(/bin/mktemp -q /tmp/$IPSET.XXXXXX) \
&& CLEAN_FILES+=" $TMP_FILE" \ # Save each set in a separate file
&& chmod 600 "$TMP_FILE" \ mkdir -p ${IPSET_DATA_DIR}
&& ${IPSET_BIN} save > $TMP_FILE 2>/dev/null \ chmod 0700 ${IPSET_DATA_DIR}
&& [[ -s $TMP_FILE ]] \ IFS="
|| ret=1 "
for set in $(${IPSET_BIN} list -n -t); do
if [[ $ret -eq 0 ]]; then # Empty name allowed, use ".set" as suffix. 'ipset save' doesn't
# No need to do anything if the files are the same # quote set names with spaces: if we have a space in the name,
if [[ ! -f $IPSET_DATA ]]; then # work around this by quoting it ourselves in the output.
mv $TMP_FILE $IPSET_DATA && chmod 600 $IPSET_DATA || ret=1 # shellcheck disable=SC2003 # No POSIX equivalent to expr index
else if expr index "${set}" " " >/dev/null; then
diff -q $TMP_FILE $IPSET_DATA >/dev/null :> "${IPSET_DATA_DIR}/${set}.set"
for line in $(${IPSET_BIN} save "${set}"); do
if [[ $? -ne 0 ]]; then create=0
if [[ -f $IPSET_DATA ]]; then echo "${line}" | grep -q "^create " && create=1
cp -f --preserve=timestamps $IPSET_DATA $IPSET_DATA.save \ if [ $create -eq 1 ]; then
&& chmod 600 $IPSET_DATA.save \ line=${line#create *}
|| ret=1 else
line=${line#add *}
fi
line=${line#${set} *}
set="$(echo "${set}" | sed 's/"/\\"/g')"
if [ $create -eq 1 ]; then
echo "create \"${set}\" ${line}" >> "${IPSET_DATA_DIR}/${set}.set"
else
echo "add \"${set}\" ${line}" >> "${IPSET_DATA_DIR}/${set}.set"
fi
done
else
${IPSET_BIN} save "${set}" > "${IPSET_DATA_DIR}/${set}.set" || fail=1
fi fi
if [[ $ret -eq 0 ]]; then [ -f "${IPSET_DATA_DIR}/${set}.set" ] && chmod 600 "${IPSET_DATA_DIR}/${set}.set"
cp -f --preserve=timestamps $TMP_FILE $IPSET_DATA \ [ $fail -eq 1 ] && err "Cannot save set ${set}" && unset IFS && return 1
&& chmod 600 $IPSET_DATA \ done
|| ret=1 touch ${IPSET_DATA_SAVED_FLAG} || { unset IFS; return 1; }
fi unset IFS
fi
fi # Done: remove backups
fi rm -rf ${IPSET_DATA_DIR_BACKUP}
rm -rf ${IPSET_DATA_COMPAT_BACKUP}
rm -f $TMP_FILE
return $ret return 0
} }
# Generate a grep regexp matching abbreviated command forms. E.g., for create:
# \(c\|cr\|cre\|crea\|creat\|create\)
cmd_short_expr() {
out=
cmd_len=1
while [ "${cmd_len}" -le "${#1}" ]; do
[ -z "${out}" ] && out='\(' || out="${out}"'\|'
# shellcheck disable=SC2003 # No POSIX equivalent to expr substr
out="${out}$(expr substr "${1}" 1 "${cmd_len}")"
cmd_len=$((cmd_len + 1))
done
echo "${out}"'\)'
}
ipset_restore() {
file="${1}"
retfile="$(mktemp -q /tmp/ipset.XXXXXX)"
CLEAN_FILES="${CLEAN_FILES} ${retfile}"
# If restore fails due to invalid lines, remove them and retry
while ! restore_err="$( (${IPSET_BIN} -f "${file}" -! restore 2>&1; echo $? >"${retfile}") | head -n1; exit "$(cat "${retfile}")" )"; do
warn "${restore_err}"
case ${restore_err#*: } in
"No command specified"*)
line="$(grep -m1 -n "^${restore_err##* }" "${file}")"
line="${line%:*}"
;;
"Missing second mandatory argument to command "*)
cmd="${restore_err##* }"
cmd_expr="$(cmd_short_expr "${cmd}")"
line="$(grep -n '^'"${cmd_expr}" "${file}" | grep -m1 -v '^[0-9]\+\:'"${cmd_expr}"'[[:blank:]]\+[^[:blank:]]\+[[:blank:]]\+[^[:blank:]]\+')"
line="${line%:*}"
;;
"Missing mandatory argument to command "*)
cmd="${restore_err##* }"
cmd_expr="$(cmd_short_expr "${cmd}")"
line="$(grep -n '^'"${cmd_expr}" "${file}" | grep -m1 -v '^[0-9]\+\:'"${cmd_expr}"'[[:blank:]]\+[^[:blank:]]\+')"
line="${line%:*}"
;;
"Command "*"is invalid in restore mode"*)
restore_err_cmd="${restore_err#*: }"
restore_err_cmd="${restore_err_cmd#*\`}"
restore_err_cmd="${restore_err_cmd%%\'*}"
cmd="${restore_err_cmd##* }"
cmd_expr="$(cmd_short_expr "${cmd}")"
line="$(grep -m1 -ne '^'"${cmd_expr}"'[[:blank:]]\+' -e '^'"${restore_err_cmd}"'$' "${file}")"
line="${line%:*}"
;;
"Error in line "*)
line="${restore_err%: *}"
line="${line##* }"
;;
*)
rm "${retfile}"
CLEAN_FILES="${CLEAN_FILES%* ${retfile}}"
return 1
;;
esac
[ -z "${line}" ] && return 1
warn "Skipped invalid entry: $(sed "${line}q;d" "${file}")"
sed -i -e "${line}d" "${file}"
[ -s "${file}" ] || return 1
done
rm "${retfile}"
CLEAN_FILES="${CLEAN_FILES%* ${retfile}}"
}
load() {
if [ -f ${IPSET_DATA_SAVED_FLAG} ]; then
# If we have a cleanly saved directory with all sets, we can
# delete any left-overs and use it
rm -rf ${IPSET_DATA_DIR_BACKUP}
rm -f ${IPSET_DATA_COMPAT_BACKUP}
else
# If sets weren't cleanly saved, restore from backups
[ -d ${IPSET_DATA_DIR_BACKUP} ] && rm -rf ${IPSET_DATA_DIR} && mv -Tf ${IPSET_DATA_DIR_BACKUP} ${IPSET_DATA_DIR}
[ -f ${IPSET_DATA_COMPAT_BACKUP} ] && rm -f ${IPSET_DATA_COMPAT} && mv -Tf ${IPSET_DATA_COMPAT_BACKUP} ${IPSET_DATA_COMPAT}
fi
if [ ! -d ${IPSET_DATA_DIR} ] && [ ! -f ${IPSET_DATA_COMPAT} ]; then
info "No existing configuration available, none loaded"
touch ${IPSET_RUN}
return
fi
# Merge all sets into temporary file
merged="$(mktemp -q /tmp/ipset.XXXXXX)"
CLEAN_FILES="${CLEAN_FILES} ${merged}"
chmod 600 "${merged}"
set +f
if [ -d ${IPSET_DATA_DIR} ]; then
# Copy create commands from each saved set first, then the rest:
# list:set entries depend on other sets, so make sure they all
# get created first
for f in "${IPSET_DATA_DIR}"/*; do
[ "${f}" = "${IPSET_DATA_DIR}/*" ] && break
[ -f "${f}" ] || continue
grep '^c' "${f}" >> "${merged}"
done
for f in "${IPSET_DATA_DIR}"/*; do
[ "${f}" = "${IPSET_DATA_DIR}/*" ] && break
[ -f "${f}" ] || continue
grep -v '^c' "${f}" >> "${merged}"
done
fi
set -f
[ -f ${IPSET_DATA_COMPAT} ] && cat ${IPSET_DATA_COMPAT} >> "${merged}"
# Drop sets that aren't in saved data, mark conflicts with existing sets
conflicts=""
IFS="
"
for set in $(${IPSET_BIN} list -n -t); do
grep -q "^create ${set} " "${merged}" && conflicts="${conflicts}|${set}" && continue
# We can't destroy the set if it's in use, flush it instead
if ! ${IPSET_BIN} destroy "${set}" 2>/dev/null; then
${IPSET_BIN} flush "${set}"
fi
done
unset IFS
conflicts="${conflicts#|*}"
# Common case: if we have no conflicts, just restore in one shot
if [ -z "${conflicts}" ]; then
if ! ipset_restore "${merged}"; then
err "Failed to restore configured sets"
exit 1
fi
rm "${merged}"
CLEAN_FILES="${CLEAN_FILES%* ${merged}}"
touch ${IPSET_RUN}
return
fi
# Find a salt for md5sum that makes names of saved sets unique
salt=0
while true; do
unique=1
IFS="
"
for set in $(${IPSET_BIN} list -n -t); do
if grep -q "^create $(echo "${salt}${set}" | md5sum | head -c31) " "${merged}"; then
unique=0
break
fi
done
unset IFS
[ ${unique} -eq 1 ] && break
salt=$((salt + 1))
done
# Add sets, mangling names for conflicting sets
mangled="$(mktemp -q /tmp/ipset.XXXXXX)"
CLEAN_FILES="${CLEAN_FILES} ${mangled}"
chmod 600 "${mangled}"
cat "${merged}" > "${mangled}"
IFS='|'
for set in ${conflicts}; do
new_name=$(echo "${salt}${set}" | md5sum | head -c31)
echo "s/^(add|create) $set /\1 $new_name /"
done | sed -i -r -f - "${mangled}"
unset IFS
if ! ipset_restore "${mangled}"; then
err "Failed to restore configured sets"
exit 1
fi
rm "${mangled}"
CLEAN_FILES="${CLEAN_FILES%* ${mangled}}"
# Swap and delete old sets
IFS='|'
for set in ${conflicts}; do
mangled="$(echo "${salt}${set}" | md5sum | head -c31)"
if ! ${IPSET_BIN} swap "${set}" "${mangled}" 2>/dev/null; then
# This fails if set types are different: try to destroy
# existing set
if ! ${IPSET_BIN} destroy "${set}" 2>/dev/null; then
# Conflicting set is in use, we can only warn
# and flush the existing set
err "Cannot load set \"${set}\", set with same name and conflicting type in use"
${IPSET_BIN} flush "${set}"
${IPSET_BIN} destroy "${mangled}"
else
${IPSET_BIN} rename "${mangled}" "${set}"
fi
else
${IPSET_BIN} destroy "${mangled}"
fi
done
unset IFS
rm "${merged}"
CLEAN_FILES="${CLEAN_FILES%* ${merged}}"
touch ${IPSET_RUN}
}
cleanup() {
${IPSET_BIN} flush || err "Failed to flush sets"
# Try to destroy all sets at once. This will fail if some are in use,
# destroy all the other ones in that case
${IPSET_BIN} destroy 2>/dev/null && return
IFS="
"
for set in $(${IPSET_BIN} list -n -t); do
if ! ${IPSET_BIN} destroy "${set}"; then
err "Failed to destroy set ${set}"
fi
done
unset IFS
}
stop() {
[ -f ${IPSET_RUN} ] || { info "Not running"; return 0; }
[ "${IPSET_SAVE_ON_STOP}" = "yes" ] && { save || err "Failed to save sets"; }
# Nothing to stop if the ip_set module is not loaded
lsmod | grep -q "^ip_set " || { info "Not running"; rm ${IPSET_RUN}; return 0; }
# If the xt_set module is in use, then iptables is using ipset, so
# refuse to stop the service
if mod="$(lsmod | grep ^xt_set)"; then
if [ "$(echo "${mod}" | tr -s ' ' | cut -d' ' -f3)" != "0" ]; then
err "Current iptables configuration requires ipset" && return 1
fi
fi
cleanup
rm ${IPSET_RUN}
return 0
}
lock
case "$1" in case "$1" in
start) start)
start load
RETVAL=$?
;; ;;
stop) stop)
check_can_unload || exit 1
[[ $IPSET_SAVE_ON_STOP = yes ]] && save
stop stop
RETVAL=$?
[[ $RETVAL -eq 6 ]] && echo "${IPSET}: not running" && exit 0
;; ;;
reload) reload)
[[ $IPSET_SAVE_ON_RESTART = yes ]] && save cleanup
stop load
RETVAL=$?
[[ $RETVAL -eq 6 ]] && echo "${IPSET}: not running" && exit 0
start
RETVAL=$?
;; ;;
*) save)
echo "Usage: $IPSET {start|stop|reload}" >&2 save
;;
*)
info "Usage: $0 {start|stop|reload|save}"
exit 1 exit 1
esac esac
exit $RETVAL exit $?