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