[ipset] Add a service subpackage

Mathieu Bridon bochecha at fedoraproject.org
Fri Aug 30 06:02:34 UTC 2013


commit e4af967234ab2edaf2d3bf27ea8191f76c10f908
Author: Quentin Armitage <quentin at armitage.org.uk>
Date:   Fri Aug 30 13:49:08 2013 +0800

    Add a service subpackage
    
    This contains a systemd unit, and the logic to be able to save and
    reload functionality on shutdown/startup.
    
    This also adds a missing explicit dependency on the ipset-libs
    subpackage in the base package. It is needed to cover the case where a
    user would update one explicitly (e.g yum update ipset) as they need to
    be kept in sync.

 ipset.service    |   18 +++++
 ipset.spec       |   62 +++++++++++++++-
 ipset.start-stop |  209 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 285 insertions(+), 4 deletions(-)
---
diff --git a/ipset.service b/ipset.service
new file mode 100644
index 0000000..f86c16b
--- /dev/null
+++ b/ipset.service
@@ -0,0 +1,18 @@
+[Unit]
+Description=IP sets for iptables
+Before=iptables.service
+Before=ip6tables.service
+
+[Service]
+Type=oneshot
+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.
+#   Value: yes|no,  default: no
+# Saves all ipsets to /etc/sysconfig/ipset if ipset gets stopped
+Environment=IPSET_SAVE_ON_STOP=no IPSET_SAVE_ON_RESTART=no
+
+[Install]
+WantedBy=basic.target
diff --git a/ipset.spec b/ipset.spec
index 6dfef48..55a42ff 100644
--- a/ipset.spec
+++ b/ipset.spec
@@ -1,17 +1,33 @@
 Name:          ipset
 Version:       6.19
-Release:       1%{?dist}
+Release:       2%{?dist}
 Summary:       Manage Linux IP sets
 
 License:       GPLv2
 URL:           http://ipset.netfilter.org/
 Source0:       http://ipset.netfilter.org/%{name}-%{version}.tar.bz2
-
+Source1:       %{name}.service
+Source2:       %{name}.start-stop
 BuildRequires: libmnl-devel
+Requires:      %{name}-libs%{?_isa} = %{version}-%{release}
 
-# This is developped hand in hand with a kernel module
+# This is developed hand in hand with a kernel module
 Requires:      kernel
 
+%package service
+Summary:       %{name} service for %{name}s
+Requires:      %{name} = %{version}-%{release}
+BuildRequires: systemd
+Requires:      iptables-services
+Requires(post): systemd
+Requires(preun): systemd
+Requires(postun): systemd
+BuildArch:     noarch
+
+%description service
+This package provides the service %{name} that is split
+out of the base package since it is not active by default.
+
 %description
 IP sets are a framework inside the Linux 2.4.x and 2.6.x kernel, which can be
 administered by the ipset utility. Depending on the type, currently an IP set
@@ -65,9 +81,37 @@ make %{?_smp_mflags}
 make install DESTDIR=%{buildroot}
 find %{buildroot} -name '*.la' -exec rm -f '{}' \;
 
+# install systemd unit file
+install -d -m 755 %{buildroot}/%{_unitdir}
+install -c -m 644 %{SOURCE1} %{buildroot}/%{_unitdir}
 
-%post libs -p /sbin/ldconfig
+# install supporting script
+install -d -m 755 %{buildroot}%{_libexecdir}/%{name}
+install -c -m 755 %{SOURCE2} %{buildroot}%{_libexecdir}/%{name}
+
+# Create directory for configuration
+mkdir -p %{buildroot}%{_sysconfdir}/%{name}
+
+%preun
+if [[ $1 -eq 0 && -n $(lsmod | grep "^xt_set ") ]]; then
+    rmmod xt_set 2>/dev/null
+    [[ $? -ne 0 ]] && echo Current iptables configuration requires ipsets && exit 1
+fi
 
+%post service
+%systemd_post %{name}.service
+
+%preun service
+if [[ $1 -eq 0 && -n $(lsmod | grep "^xt_set ") ]]; then
+    rmmod xt_set 2>/dev/null
+    [[ $? -ne 0 ]] && echo Current iptables configuration requires ipsets && exit 1
+fi
+%systemd_preun %{name}.service
+
+%postun service
+%systemd_postun_with_restart %{name}.service
+
+%post libs -p /sbin/ldconfig
 
 %postun libs -p /sbin/ldconfig
 
@@ -81,12 +125,22 @@ find %{buildroot} -name '*.la' -exec rm -f '{}' \;
 %doc COPYING
 %{_libdir}/lib%{name}.so.3*
 
+%files service
+%{_unitdir}/%{name}.service
+%dir %{_libexecdir}/%{name}
+%attr(0755,root,root) %{_libexecdir}/%{name}/%{name}.start-stop
+%dir %{_sysconfdir}/%{name}
+
 %files devel
 %{_includedir}/lib%{name}
 %{_libdir}/lib%{name}.so
 
 
 %changelog
+* Tue Aug 27 2013 Quentin Armitage <quentin at armitage.org.uk> 6.19-2
+- Add service pkg - adds save and reload functionality on shutdown/startup
+- Add requires dependency of ipset on matching ipset-libs
+
 * Thu Aug 15 2013 Mathieu Bridon <bochecha at fedoraproject.org> - 6.19
 - New upstream release.
 
diff --git a/ipset.start-stop b/ipset.start-stop
new file mode 100644
index 0000000..da21890
--- /dev/null
+++ b/ipset.start-stop
@@ -0,0 +1,209 @@
+#!/bin/bash
+#
+# 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
+}
+
+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
+}
+
+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
+}
+
+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
+}
+
+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
+		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
+}
+
+
+case "$1" in
+    start)
+	start
+	RETVAL=$?
+	;;
+    stop)
+	check_can_unload || exit 1
+	[[ $IPSET_SAVE_ON_STOP = yes ]] && save
+	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=$?
+	;;
+    *)
+	echo "Usage: $IPSET {start|stop|reload}" >&2
+	exit 1
+esac
+
+exit $RETVAL


More information about the scm-commits mailing list