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
ExecStop=/usr/libexec/ipset/ipset.start-stop stop
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
# Saves all ipsets to /etc/ipset/ipset if ipset gets stopped
Environment=IPSET_SAVE_ON_STOP=no IPSET_SAVE_ON_RESTART=no
# Saves all ipsets to /etc/sysconfig/ipset if ipset gets stopped
Environment=IPSET_SAVE_ON_STOP=no
EnvironmentFile=-/etc/sysconfig/ipset-config
[Install]
WantedBy=basic.target

View File

@ -1,16 +1,17 @@
Name: ipset
Version: 7.15
Release: 2
Version: 7.17
Release: 1
Summary: Manage Linux IP sets
License: GPLv2
URL: http://ipset.netfilter.org/
Source0: http://ipset.netfilter.org/%{name}-%{version}.tar.bz2
Source1: ipset.service
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(post): systemd
Requires(preun): systemd
@ -71,12 +72,27 @@ install -c -m 644 %{SOURCE1} %{buildroot}/%{_unitdir}
install -d -m 755 %{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}
%ldconfig_scriptlets libs
%post
%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
if [[ $1 -eq 0 && -n $(lsmod | grep "^xt_set ") ]]; then
@ -97,6 +113,8 @@ fi
%{_unitdir}/ipset.service
%{_libexecdir}/ipset/ipset.start-stop
%{_sysconfdir}/%{name}
%config(noreplace) %attr(0600,root,root) %{_sysconfdir}/sysconfig/ipset-config
%ghost %config(noreplace) %attr(0600,root,root) %{_sysconfdir}/sysconfig/ipset
%files libs
%defattr(-,root,root)
@ -116,6 +134,12 @@ fi
%{_mandir}/man3/libipset.3.*
%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
- Type:bugfix
- ID:NA

View File

@ -1,209 +1,359 @@
#!/bin/bash
#!/bin/sh
#
# ipset Start and stop ipset firewall sets
#
# config: /etc/ipset/ipset
#
IPSET=ipset
IPSET_BIN=/usr/sbin/${IPSET}
IPSET_DATA=/etc/${IPSET}/${IPSET}
IPTABLES_CONFIG=/etc/sysconfig/iptables-config
IP6TABLES_CONFIG=${IPTABLES_CONFIG/iptables/ip6tables}
TMP_FIFO=/tmp/${IPSET}.$$
if [[ ! -x ${IPSET_BIN} ]]; then
echo "${IPSET_BIN} does not exist."
exit 5
fi
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
# config: /etc/sysconfig/ipset-config
IPSET_BIN=/usr/sbin/ipset
IPSET_CONFIG=/etc/sysconfig/ipset-config
IPSET_DATA_COMPAT=/etc/sysconfig/ipset
IPSET_DATA_COMPAT_BACKUP=${IPSET_DATA_COMPAT}.save
IPSET_DATA_DIR=/etc/sysconfig/ipset.d
IPSET_DATA_DIR_BACKUP=${IPSET_DATA_DIR}.save
IPSET_DATA_SAVED_FLAG=${IPSET_DATA_DIR}/.saved
IPSET_LOCK=/run/ipset.lock
IPSET_RUN=/run/ipset.run
CLEAN_FILES=""
trap "rm -rf \${CLEAN_FILES}" EXIT
info() {
echo "ipset: ${*}" >&2
}
flush_n_delete() {
local ret=0 set
# 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
warn() {
echo "<4>ipset: ${*}" >&2
}
start_clean()
{
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
err() {
echo "<3>ipset: ${*}" >&2
}
start() {
# Do not start if there is no config file.
[[ ! -f "$IPSET_DATA" ]] && echo "Loaded with no configuration" && return 0
# We can skip the first bit and do a simple load if
# there is no current ipset configuration
res=1
if [[ -n $(${IPSET_BIN} list -name) ]]; then
# The following may fail for some bizarre reason
start_clean
res=$?
[[ $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
[ -x ${IPSET_BIN} ] || { err "Cannot execute ${IPSET_BIN}"; exit 1; }
# Source ipset configuration
# shellcheck source=ipset-config
[ -f ${IPSET_CONFIG} ] && . ${IPSET_CONFIG}
set -f
lock() {
CLEAN_FILES="${CLEAN_FILES} ${IPSET_LOCK}"
until mkdir ${IPSET_LOCK} 2>/dev/null; do :; done
}
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() {
# Do not save if ip_set module is not loaded.
lsmod | grep -q "^ip_set "
[[ $? -ne 0 ]] && return 6
[[ -z $(${IPSET_BIN} list -name) ]] && return 0
ret=0
TMP_FILE=$(/bin/mktemp -q /tmp/$IPSET.XXXXXX) \
&& CLEAN_FILES+=" $TMP_FILE" \
&& chmod 600 "$TMP_FILE" \
&& ${IPSET_BIN} save > $TMP_FILE 2>/dev/null \
&& [[ -s $TMP_FILE ]] \
|| ret=1
if [[ $ret -eq 0 ]]; then
# No need to do anything if the files are the same
if [[ ! -f $IPSET_DATA ]]; then
mv $TMP_FILE $IPSET_DATA && chmod 600 $IPSET_DATA || ret=1
else
diff -q $TMP_FILE $IPSET_DATA >/dev/null
if [[ $? -ne 0 ]]; then
if [[ -f $IPSET_DATA ]]; then
cp -f --preserve=timestamps $IPSET_DATA $IPSET_DATA.save \
&& chmod 600 $IPSET_DATA.save \
|| ret=1
fail=0
# Make backups of existing configuration first, if any
[ -d ${IPSET_DATA_DIR} ] && mv -Tf ${IPSET_DATA_DIR} ${IPSET_DATA_DIR_BACKUP}
[ -f ${IPSET_DATA_COMPAT} ] && mv -Tf ${IPSET_DATA_COMPAT} ${IPSET_DATA_COMPAT_BACKUP}
rm -f ${IPSET_DATA_SAVED_FLAG}
# Save each set in a separate file
mkdir -p ${IPSET_DATA_DIR}
chmod 0700 ${IPSET_DATA_DIR}
IFS="
"
for set in $(${IPSET_BIN} list -n -t); do
# Empty name allowed, use ".set" as suffix. 'ipset save' doesn't
# quote set names with spaces: if we have a space in the name,
# work around this by quoting it ourselves in the output.
# shellcheck disable=SC2003 # No POSIX equivalent to expr index
if expr index "${set}" " " >/dev/null; then
:> "${IPSET_DATA_DIR}/${set}.set"
for line in $(${IPSET_BIN} save "${set}"); do
create=0
echo "${line}" | grep -q "^create " && create=1
if [ $create -eq 1 ]; then
line=${line#create *}
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
if [[ $ret -eq 0 ]]; then
cp -f --preserve=timestamps $TMP_FILE $IPSET_DATA \
&& chmod 600 $IPSET_DATA \
|| ret=1
fi
fi
fi
fi
rm -f $TMP_FILE
return $ret
[ -f "${IPSET_DATA_DIR}/${set}.set" ] && chmod 600 "${IPSET_DATA_DIR}/${set}.set"
[ $fail -eq 1 ] && err "Cannot save set ${set}" && unset IFS && return 1
done
touch ${IPSET_DATA_SAVED_FLAG} || { unset IFS; return 1; }
unset IFS
# Done: remove backups
rm -rf ${IPSET_DATA_DIR_BACKUP}
rm -rf ${IPSET_DATA_COMPAT_BACKUP}
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
start)
start
RETVAL=$?
start)
load
;;
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)
[[ $IPSET_SAVE_ON_RESTART = yes ]] && save
stop
RETVAL=$?
[[ $RETVAL -eq 6 ]] && echo "${IPSET}: not running" && exit 0
start
RETVAL=$?
reload)
cleanup
load
;;
*)
echo "Usage: $IPSET {start|stop|reload}" >&2
save)
save
;;
*)
info "Usage: $0 {start|stop|reload|save}"
exit 1
esac
exit $RETVAL
exit $?