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