xref: /illumos-gate/usr/src/cmd/ipf/svc/ipfilter (revision 2bd8b354)
1#!/sbin/sh
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22#
23# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26# Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
27#
28
29. /lib/svc/share/smf_include.sh
30. /lib/svc/share/ipf_include.sh
31
32PATH=${PATH}:/usr/sbin:/usr/lib/ipf
33PIDFILE=/var/run/ipmon.pid
34PFILCHECKED=no
35
36zone=`smf_zonename`
37ipfid=`/usr/sbin/modinfo 2>&1 | awk '/ipf/ { print $1 } ' - 2>/dev/null`
38if [ -f $PIDFILE ] ; then
39	pid=`cat $PIDFILE 2>/dev/null`
40else
41	pid=`pgrep -z $zone ipmon`
42fi
43
44logmsg()
45{
46	logger -p daemon.warning -t ipfilter "$1"
47	echo "$1" >&2
48}
49
50load_ipf() {
51	bad=0
52	ipf -IFa
53	ipf -6IFa
54
55	for file in $IPFILOVRCONF $CONF_FILES $IPFILCONF; do
56		if [ -r ${file} ]; then
57			ipf -I -f ${file}
58			if [ $? != 0 ]; then
59				echo "$0: load of ${file} into alternate" \
60				    "set failed"
61				bad=1
62			fi
63		fi
64	done
65
66	for file in $IP6FILOVRCONF $CONF6_FILES $IP6FILCONF; do
67		if [ -r ${file} ]; then
68			ipf -6I -f ${file}
69			if [ $? != 0 ]; then
70				echo "$0: load of ${file} into alternate set failed"
71				bad=1
72			fi
73		fi
74	done
75
76	if [ $bad -eq 0 ] ; then
77		ipf -s -y
78		return 0
79	else
80		echo "Not switching config due to load error."
81		return 1
82	fi
83}
84
85
86load_ipnat() {
87	ipnat -CF
88	for nfile in $NAT_FILES $IPNATCONF; do
89		if [ -r ${nfile} ]; then
90			ipnat -f ${nfile}
91			if [ $? != 0 ]; then
92				echo "$0: load of ${nfile} failed"
93				return 1
94			else
95				ipf -y
96			fi
97		fi
98	done
99}
100
101
102load_ippool() {
103	if [ -r ${IPPOOLCONF} ]; then
104		ippool -F
105		ippool -f ${IPPOOLCONF}
106		if [ $? != 0 ]; then
107			echo "$0: load of ${IPPOOLCONF} failed"
108			return 1
109		else
110			return 0
111		fi
112	else
113		return 0
114	fi
115}
116
117#
118# Get current configuration version, fails if property doesn't exist.
119#
120config_get_version()
121{
122        ver=`svcprop -p $FW_CONFIG_DEF_PG/version $SMF_FMRI 2>/dev/null`
123        [ $? -ne 0 -o -z "$ver" ] && return 1
124
125        echo "$ver"
126}
127
128#
129# Version 1 configuration migration - if there's an existing ipf.conf file, set
130# the default system-wide policy to "custom" and set the custom file value to
131# "/etc/ipf/ipf.conf". Do this migration once and set the 'version' property
132# to the current version value.
133#
134upgrade_config()
135{
136	old_ipfconf="/etc/ipf/ipf.conf"
137
138	if [ -f ${old_ipfconf} ]; then
139		grep '^[ \t]*[^# \t]' ${old_ipfconf} >/dev/null 2>&1
140		if [ $? -eq 0 ]; then
141			svccfg -s $SMF_FMRI setprop \
142			    $FW_CONFIG_DEF_PG/$POLICY_PROP = astring: \
143			    "custom" >/dev/null 2>&1
144			svccfg -s $SMF_FMRI setprop \
145			    $FW_CONFIG_DEF_PG/$CUSTOM_FILE_PROP = astring: \
146			    "$old_ipfconf" >/dev/null 2>&1
147		fi
148	fi
149
150	svccfg -s $SMF_FMRI setprop $FW_CONFIG_DEF_PG/version = count: \
151	    "$CURRENT_VERSION" >/dev/null 2>&1
152	svcadm refresh $SMF_FMRI >/dev/null 2>&1
153}
154
155configure_firewall()
156{
157	create_global_rules || exit $SMF_EXIT_ERR_CONFIG
158	create_global_ovr_rules || exit $SMF_EXIT_ERR_CONFIG
159	create_services_rules || exit $SMF_EXIT_ERR_CONFIG
160
161	[ ! -f ${IPFILCONF} -a ! -f ${IPNATCONF} ] && exit 0
162	ipf -E
163	load_ippool || exit $SMF_EXIT_ERR_CONFIG
164	load_ipf || exit $SMF_EXIT_ERR_CONFIG
165	load_ipnat || exit $SMF_EXIT_ERR_CONFIG
166}
167
168#
169# We handle configuration migration as well as a model change (transient to
170# contract based service) in the start, stop, and refresh methods.
171#
172# Configuration migration is straightforward, the start method will do the
173# upgrade if the repository version value is not the same as the version
174# defined in ipf_include.sh However, there are two problems. First, ipfilter
175# can start in parallel with manifest-import, thus the new configuration
176# properties and service definition may not be available to the start method
177# on the first reboot after an upgrade. Second, a transient to contract based
178# model change isn't well supported for an online service.
179#
180# - If the start method finds the property missing (manifest-import hasn't
181# completed), it will allow the still transient network/ipfilter to stay
182# 'online' and wait for manifest-import. Once manifest-import completes, the
183# refresh method will run svcadm restart if the version value is not
184# up-to-date and the subsequent start method will perform the upgrade.
185#
186# - Since the start method allows the service to stay online as a transient
187# service (no contract), the svcadm restart invoked by refresh (described
188# above) will result in a call to the stop method with no existing contract
189# property. The ipfilter manifest cannot include contract/restarter token in
190# its stop method definition since startd will fail to expand that token and
191# place the service in maintenance. Thus, the stop method has to explicitly
192# get the contract id before calling smf_kill_contract.
193#
194case "$1" in
195	start)
196		ver=`config_get_version`
197		if [ $? -eq 1 ]; then
198			echo "Warning: firewall properties are not available"
199			exit $SMF_EXIT_OK
200		fi
201
202		[ "$ver" -ne "$CURRENT_VERSION" ] && upgrade_config
203
204		configure_firewall
205
206		/lib/svc/bin/svc.ipfd
207		/usr/sbin/ipmon -Ds
208		;;
209
210	stop)
211		ctid=`svcprop -p restarter/contract $SMF_FMRI`
212		if [ -n "$ctid" ]; then
213			smf_kill_contract $ctid TERM 1
214		fi
215
216		ipf -D
217		[ "$zone" = "global" -a -n "$ipfid" ] && modunload -i $ipfid
218		;;
219
220	pause)
221		ipfs -l
222		ipfs -d /var/db/ipf -W
223		ipf -D
224		if [ -f $PIDFILE ] ; then
225			if kill -0 $pid; then
226				kill -TERM $pid
227			else
228				cp /dev/null $PIDFILE
229			fi
230		fi
231		;;
232
233	resume)
234		ipf -E
235		ipfs -R
236		load_ippool
237		load_ipf
238		load_ipnat
239		if [ -f $PIDFILE -a -n "$pid" ] ; then
240			/usr/sbin/ipmon -Ds
241		fi
242		;;
243
244	reload)
245		ver=`config_get_version`
246		if [ $? -eq 1 ]; then
247			echo "Warning: firewall properties are not available"
248			exit $SMF_EXIT_ERR_CONFIG
249		fi
250
251		if [ "$ver" -ne "$CURRENT_VERSION" ]; then
252			svcadm restart $SMF_FMRI
253			exit $SMF_EXIT_OK
254		fi
255
256		configure_firewall
257		;;
258
259	reipf)
260		load_ipf
261		;;
262
263	reipnat)
264		load_ipnat
265		;;
266
267	fw_update)
268		#
269		# The second argument is the fmri of the service to be updated.
270		# If it's the network/ipfilter, we want to repopulate firewall
271		# configuration for the entire system.
272		#
273		if [ "$2" = "$SMF_FMRI" ]; then
274			configure_firewall
275		else
276			service_update $2 || exit 1
277		fi
278		;;
279
280	*)
281		echo "Usage: $0 \c" >&2
282		echo "(start|stop|reload|reipf|reipnat|pause|resume)" >&2
283		exit 1
284		;;
285
286esac
287exit $SMF_EXIT_OK
288