#!/sbin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2016 Hans Rosenfeld # setvar IPFILTER_FMRI = ""svc:/network/ipfilter:default"" setvar ETC_IPF_DIR = '/etc/ipf' setvar IPNATCONF = $(/usr/bin/svcprop -p config/ipnat_config_file $IPFILTER_FMRI \ ) if test $Status -eq 1 { setvar IPNATCONF = "$ETC_IPF_DIR/ipnat.conf" } setvar IPPOOLCONF = $(/usr/bin/svcprop -p config/ippool_config_file $IPFILTER_FMRI \ ) if test $Status -eq 1 { setvar IPPOOLCONF = "$ETC_IPF_DIR/ippool.conf" } setvar VAR_IPF_DIR = '/var/run/ipf' setvar IPFILCONF = "$VAR_IPF_DIR/ipf.conf" setvar IP6FILCONF = "$VAR_IPF_DIR/ipf6.conf" setvar IPFILOVRCONF = "$VAR_IPF_DIR/ipf_ovr.conf" setvar IP6FILOVRCONF = "$VAR_IPF_DIR/ipf6_ovr.conf" setvar IPF_LOCK = '/var/run/ipflock' setvar CONF_FILES = """" setvar CONF6_FILES = """" setvar NAT_FILES = """" setvar IPF_SUFFIX = "".ipf"" setvar IPF6_SUFFIX = "".ipf6"" setvar NAT_SUFFIX = "".nat"" # version for configuration upgrades setvar CURRENT_VERSION = '1' setvar IPF_FMRI = ""svc:/network/ipfilter:default"" setvar INETDFMRI = ""svc:/network/inetd:default"" setvar RPCBINDFMRI = ""svc:/network/rpc/bind:default"" setvar SMF_ONLINE = ""online"" setvar SMF_MAINT = ""maintenance"" setvar SMF_NONE = ""none"" setvar FW_CONTEXT_PG = ""firewall_context"" setvar METHOD_PROP = ""ipf_method"" setvar FW_CONFIG_PG = ""firewall_config"" setvar POLICY_PROP = ""policy"" setvar APPLY2_PROP = ""apply_to"" setvar APPLY2_6_PROP = ""apply_to_6"" setvar EXCEPTIONS_PROP = ""exceptions"" setvar EXCEPTIONS_6_PROP = ""exceptions_6"" setvar TARGET_PROP = ""target"" setvar TARGET_6_PROP = ""target_6"" setvar BLOCKPOL_PROP = ""block_policy"" setvar FW_CONFIG_DEF_PG = ""firewall_config_default"" setvar FW_CONFIG_OVR_PG = ""firewall_config_override"" setvar CUSTOM_FILE_PROP = ""custom_policy_file"" setvar CUSTOM_FILE_6_PROP = ""custom_policy_file_6"" setvar OPEN_PORTS_PROP = ""open_ports"" setvar PREFIX_HOST = ""host:"" setvar PREFIX_NET = ""network:"" setvar PREFIX_POOL = ""pool:"" setvar PREFIX_IF = ""if:"" setvar GLOBAL_CONFIG = """" setvar GLOBAL_POLICY = """" setvar GLOBAL_BLOCK_POLICY = """" setvar SERVINFO = '/usr/lib/servinfo' # # Get value(s) for given property from either firewall_config_default or # firewall_config_override property groups. # # global_get_prop_value pg_name propname # pg_name - FW_CONFIG_DEF_PG or FW_CONFIG_OVR_PG # propname - property name # proc global_get_prop_value { setvar target_pg = "$1" setvar prop = "$2" test $1 != $FW_CONFIG_OVR_PG -a $1 != $FW_CONFIG_DEF_PG && return test $1 == $FW_CONFIG_DEF_PG && setvar extra_pg = "$FW_CONFIG_OVR_PG" || \ setvar extra_pg = "$FW_CONFIG_DEF_PG" setvar value = $(echo $GLOBAL_CONFIG | awk '{ found=0 for (i=1; i<=NF; i++) { if (found == 1) { if (index($i, target_pg) == 1 || index($i, extra_pg) == 1) break; print $i; } if (split($i, values, "/") < 2) continue; if (values[1] == target_pg && values[2] == prop) found=1; } }' target_pg=$target_pg prop=$prop extra_pg=$extra_pg) # Return echo $value } # # Initialize and cache network/ipfilter configuration, global configuration. # # Since an SMF service configuration may get updated during the execution of the # service method, it's best to read all relevant configuration via one svcprop # invocation and cache it for later use. # # This function reads and stores relevant configuration into GLOBAL_CONFIG and # initializes the GLOBAL_POLICY and GLOBAL_BLOCK_POLICY variables. GLOBAL_CONFIG # is a string containing pg/prop and their corresponding values (i.e. svcprop -p # pg fmri output). To get values for a certain pg/prop, use # global_get_prop_value(). # proc global_init { setvar GLOBAL_CONFIG = $(svcprop -p ${FW_CONFIG_OVR_PG} -p ${FW_CONFIG_DEF_PG} \ $IPF_FMRI 2>/dev/null | awk '{$2=" "; print $0}) setvar GLOBAL_POLICY = $(global_get_prop_value $FW_CONFIG_DEF_PG $POLICY_PROP) setvar GLOBAL_BLOCK_POLICY = $(global_get_prop_value $FW_CONFIG_DEF_PG \ $BLOCKPOL_PROP) } # # Given a service, gets its config pg name # proc get_config_pg { if test $1 = $IPF_FMRI { echo $FW_CONFIG_DEF_PG } else { echo $FW_CONFIG_PG } return 0 } # # Given a service, gets its firewall policy # proc get_policy { setvar config_pg = $(get_config_pg $1) svcprop -p $config_pg/${POLICY_PROP} $1 2>/dev/null } # # block policy can be set to "return", which will expand into # separate block rules for tcp (block return-rst ...) and all other # protocols (block return-icmp-as-dest ...) # proc get_block_policy { setvar config_pg = $(get_config_pg $1) svcprop -p $config_pg/${BLOCKPOL_PROP} $1 2>/dev/null } # # Given a service, gets its source address exceptions for IPv4 # proc get_exceptions { setvar config_pg = $(get_config_pg $1) setvar exceptions = $(svcprop -p $config_pg/${EXCEPTIONS_PROP} $1 ) echo $exceptions | sed -e 's/\\//g' } # # Given a service, gets its source address exceptions for IPv6 # proc get_exceptions_6 { setvar config_pg = $(get_config_pg $1) setvar exceptions6 = $(svcprop -p $config_pg/${EXCEPTIONS_6_PROP} $1 ) echo $exceptions6 | sed -e 's/\\//g' } # # Given a service, gets its firewalled source addresses for IPv4 # proc get_apply2_list { setvar config_pg = $(get_config_pg $1) setvar apply2 = $(svcprop -p $config_pg/${APPLY2_PROP} $1 ) echo $apply2 | sed -e 's/\\//g' } # # Given a service, gets its firewalled source addresses for IPv6 # proc get_apply2_6_list { setvar config_pg = $(get_config_pg $1) setvar apply2_6 = $(svcprop -p $config_pg/${APPLY2_6_PROP} $1 ) echo $apply2_6 | sed -e 's/\\//g' } # # Given a service, gets its firewalled target addresses for IPv4 # proc get_target_list { setvar config_pg = $(get_config_pg $1) setvar target = $(svcprop -p $config_pg/${TARGET_PROP} $1 ) test -z $target -o $target = '""' && setvar target = 'any' echo $target | sed -e 's/\\//g' } # # Given a service, gets its firewalled target addresses for IPv6 # proc get_target_6_list { setvar config_pg = $(get_config_pg $1) setvar target6 = $(svcprop -p $config_pg/${TARGET_6_PROP} $1 ) test -z $target6 -o $target6 = '""' && setvar target6 = 'any' echo $target6 | sed -e 's/\\//g' } proc check_ipf_dir { test -d $VAR_IPF_DIR && return 0 mkdir $VAR_IPF_DIR >/dev/null 2>&1 || return 1 } # # fmri_to_file fmri suffix # proc fmri_to_file { check_ipf_dir || return 1 setvar fprefix = ""${VAR_IPF_DIR}/$(echo $1 | tr -s '/:' '__)"" echo "${fprefix}${2}" } # # Return service's enabled property # proc service_is_enabled { # # Temporary enabled state overrides the persistent state # so check it first. # setvar enabled_ovr = $(svcprop -c -p general_ovr/enabled $1 ) if test -n $enabled_ovr { test $enabled_ovr = "true" && return 0 || return 1 } setvar enabled = $(svcprop -c -p general/enabled $1 ) test -n $enabled -a $enabled = "true" && return 0 || return 1 } # # Return whether service is desired state # # Args: fmri state # Return: # 0 - desired state is service's current state # 1 - desired state is not service's current state # proc service_check_state { # # Make sure we're done with ongoing state transition # while test $(svcprop -p restarter/next_state $1) != $SMF_NONE { sleep 1 } test $(svcprop -p restarter/state $1) = $2 && return 0 || return 1 } # # Deny/Allow list stores values in the form "host:addr", "network:addr/netmask", # "pool:number", and "if:interface". This function returns the # IP(addr or addr/netmask) value or a pool number. # proc get_IP { value_is_interface $1 && return 1 echo $1 | sed -n -e "s,^${PREFIX_POOL}\(.*\),pool/\1,p" \ -e "s,^${PREFIX_HOST}\(.*\),\1,p" \ -e "s,^${PREFIX_NET}\(.*\),\1,p" \ -e "s,^any,any,p" } proc get_interface { value_is_interface $1 || return 1 setvar scratch = $(echo $1 | sed -e "s/^${PREFIX_IF}//) ifconfig $scratch >/dev/null 2>&1 || return 1 echo $scratch | sed -e 's/:.*//' } # # # proc value_is_interface { test -z $1 && return 1 echo $1 | grep "^${PREFIX_IF}" >/dev/null 2>&1 } # # Remove rules in given file from active list without restarting ipfilter # proc remove_rules { test -f $1 && ipf $2 -r -f $1 >/dev/null 2>&1 } proc remove_nat_rules { test -f $1 && ipnat -r -f $1 >/dev/null 2>&1 } proc check_ipf_syntax { ipf $2 -n -f $1 >/dev/null 2>&1 } proc check_nat_syntax { ipnat -n -f $1 >/dev/null 2>&1 } proc unique_ports { echo $ifsjoin(ARGV) | xargs -n 1 echo | sort -u } proc file_get_ports { ipf $2 -n -v -f $1 2>/dev/null | sed -n -e \ 's/.*to.* port = \([a-z0-9]*\).*/\1/p' | uniq | \ awk '{if (length($0) > 1) {printf("%s ", $1)}}' } proc get_active_ports { ipfstat $1 -io 2>/dev/null | sed -n -e \ 's/.*to.* port = \([a-z0-9]*\).*/\1/p' | uniq | \ awk '{if (length($0) > 1) {printf("%s ",$1)}}' } # # Given two list of ports, return failure if there's a duplicate. # proc sets_check_duplicate { # # If either list is empty, there isn't any conflict. # test -z $1 -o -z $2 && return 0 for p in [$1] { for ap in [$2] { test $p = $ap && return 1 } } return 0 } # # Given a file containing ipf rules, check the syntax and verify # the rules don't conflict, use same port number, with active # rules (ipfstat -io output). # proc update_check_ipf_rules { check_ipf_syntax $1 $2 || return 1 setvar lports = $(file_get_ports $1 $2) setvar lactive_ports = $(get_active_ports $2) sets_check_duplicate $lports $lactive_ports || return 1 } setvar server_port_list = """" setvar server_port_list_6 = """" # # Given a file containing ipf rules, check the syntax and verify # the rules don't conflict with already processed services. # # The list of processed services' ports are maintained in the global # variables 'server_port_list' and 'server_port_list_6'. # proc check_ipf_rules { check_ipf_syntax $1 $2 || return 1 setvar lports = $(file_get_ports $1 $2) if test $2 = "-6" { sets_check_duplicate $lports $server_port_list_6 || return 1 setvar server_port_list_6 = ""$server_port_list_6 $lports"" } else { sets_check_duplicate $lports $server_port_list || return 1 setvar server_port_list = ""$server_port_list $lports"" } return 0 } proc prepend_new_rules { check_ipf_syntax $1 $2 && tail -r $1 | sed -e 's/^[a-z]/@0 &/' | \ ipf $2 -f - >/dev/null 2>&1 } proc append_new_rules { check_ipf_syntax $1 $2 && ipf $2 -f $1 >/dev/null 2>&1 } proc append_new_nat_rules { check_nat_syntax $1 && ipnat -f $1 >/dev/null 2>&1 } # # get port information from string of the form "proto:{port | port-port}" # proc tuple_get_port { setvar port_str = $(echo $1 | sed -e 's/ //g; s/\\\//g; s/.*://' ) test -z $port_str && return 1 echo $port_str | grep "-" >/dev/null if test $Status -eq 0 { echo $port_str | grep '^[0-9]\{1,5\}-[0-9]\{1,5\}$' >/dev/null || \ return 1 setvar ports = $(echo $port_str | shell {' IFS=-' read a b ; \ test $a '-'le $b && echo $a $b || echo $b $a }) for p in [$ports] { test $p -gt 65535 && return 1 } echo $ports } else { # # port_str is a single port, verify and return it. # echo $port_str | grep '^[0-9]\{1,5\}$' >/dev/null || return 1 test $port_str -gt 65535 && return 1 echo $port_str } } # # get proto info from string of the form "{tcp | udp}:port" # proc tuple_get_proto { setvar proto = $(echo $1 | sed -e 's/ //g; s/:.*//' ) test -z $proto && return 0 test $proto = "tcp" -o $proto = "udp" && echo $proto || return 1 return 0 } proc ipf_get_lock { setvar newpid = "$Pid" if test -f "$IPF_LOCK/pid" { setvar curpid = $(cat $IPF_LOCK/pid ) test $curpid = $newpid && return 0 # # Clear lock if the owning process is no longer around. # ps -p $curpid >/dev/null 2>&1 || rm -r $IPF_LOCK >/dev/null 2>&1 } # # Grab the lock # while : { mkdir $IPF_LOCK 2>/dev/null && break; sleep 1 } echo $newpid > $IPF_LOCK/pid } # # Remove lock if it's ours # proc ipf_remove_lock { if test -f "$IPF_LOCK/pid" { test $(cat $IPF_LOCK/pid) = "$Pid" && rm -r $IPF_LOCK } return 0 } # # Make IPFILCONF, /var/tmp/ipf/ipf.conf, a symlink to the input file argument. # proc custom_set_symlink { # # Nothing to do if the input file doesn't exist. # test ! -f $1 && return 0 check_ipf_dir || return 1 rm $IPFILCONF >/dev/null 2>&1 ln -s $1 $IPFILCONF >/dev/null 2>&1 } # # Make IP6FILCONF, /var/tmp/ipf/ipf6.conf, a symlink to the input file argument. # proc custom_set_symlink_6 { # # Nothing to do if the input file doesn't exist. # test ! -f $1 && return 0 check_ipf_dir || return 1 rm $IP6FILCONF >/dev/null 2>&1 ln -s $1 $IP6FILCONF >/dev/null 2>&1 } # # New file replaces original file if they have different content # proc replace_file { setvar orig = "$1" setvar new = "$2" # # IPFILCONF may be a symlink, remove it if that's the case # if test -L $orig { rm $orig touch $orig } check_ipf_dir || return 1 mv $new $orig && return 0 || return 1 } # # Given a service, gets the following details for ipf rule: # - policy # - protocol # - port(IANA port obtained by running servinfo) # proc process_server_svc { setvar service = "$1" setvar policy = $(get_policy ${service}) # # Empties service's rules file so callers won't use existing rule if # we fail here. # setvar file = $(fmri_to_file $service $IPF_SUFFIX) setvar file6 = $(fmri_to_file $service $IPF6_SUFFIX) test -z $file && return 1 echo "# $service" >${file} echo "# $service" >${file6} # # Nothing to do if policy is "use_global" # test $policy = "use_global" && return 0 setvar restarter = $(svcprop -p general/restarter $service ) if test $restarter = $INETDFMRI { setvar iana_name = $(svcprop -p inetd/name $service ) setvar isrpc = $(svcprop -p inetd/isrpc $service ) } else { setvar iana_name = $(svcprop -p $FW_CONTEXT_PG/name $service ) setvar isrpc = $(svcprop -p $FW_CONTEXT_PG/isrpc $service ) } # # Bail if iana_name isn't defined. Services with static rules # like nis/client don't need to generate rules using # iana name and protocol information. # test -z $iana_name && return 1 # # RPC services # if test $isrpc = "true" { # The ports used for IPv6 are usually also reachable # through IPv4, so generate IPv4 rules for them, too. setvar tports = $($SERVINFO -R -p -t -s $iana_name ) setvar tports6 = $($SERVINFO -R -p -t6 -s $iana_name ) if test -n $tports -o -n $tports6 { setvar tports = $(unique_ports $tports $tports6) for tport in [$tports] { generate_rules $service $policy "tcp" \ $tport $file } } if test -n $tports6 { for tport6 in [$tports6] { generate_rules $service $policy "tcp" \ $tport6 $file6 _6 } } setvar uports = $($SERVINFO -R -p -u -s $iana_name ) setvar uports6 = $($SERVINFO -R -p -u6 -s $iana_name ) if test -n $uports { setvar uports = $(unique_ports $uports $uports6) for uport in [$uports] { generate_rules $service $policy "udp" \ $uport $file } } if test -n $uports6 { for uport6 in [$uports6] { generate_rules $service $policy "udp" \ $uport6 $file6 _6 } } return 0 } # # Get the IANA port and supported protocols(tcp and udp) # setvar tport = $($SERVINFO -p -t -s $iana_name ) if test $Status -eq 0 -a -n $tport { generate_rules $service $policy "tcp" $tport $file } setvar tport6 = $($SERVINFO -p -t6 -s $iana_name ) if test $Status -eq 0 -a -n $tport6 { generate_rules $service $policy "tcp" $tport6 $file6 _6 } setvar uport = $($SERVINFO -p -u -s $iana_name ) if test $Status -eq 0 -a -n $uport { generate_rules $service $policy "udp" $uport $file } setvar uport6 = $($SERVINFO -p -u6 -s $iana_name ) if test $Status -eq 0 -a -n $uport6 { generate_rules $service $policy "udp" $uport6 $file6 _6 } return 0 } # # Given a service's name, policy, protocol and port, generate ipf rules # - list of host/network/interface to apply policy # # A 'use_global' policy inherits the system-wided Global Default policy # from network/ipfilter. For {deny | allow} policies, the rules are # ordered as: # # - make exceptions to policy for those in "exceptions" list # - apply policy to those specified in "apply_to" list # - policy rule # proc generate_rules { setvar service = "$1" setvar mypolicy = "$2" setvar proto = "$3" setvar port = "$4" setvar out = "$5" setvar _6 = "$6" # # Default mode is to inherit from global's policy # test $mypolicy = "use_global" && return 0 setvar tcp_opts = """" test $proto = "tcp" && setvar tcp_opts = ""flags S keep state keep frags"" setvar block_policy = $(get_block_policy $1) if test $block_policy = "use_global" { setvar block_policy = ${GLOBAL_BLOCK_POLICY} } if test $block_policy = "return" { test $proto = "tcp" && setvar block_policy = ""return-rst"" test $proto != "tcp" && setvar block_policy = ""return-icmp-as-dest"" } else { setvar block_policy = """" } setvar iplist = $(get_target${_6}_list $service) # # Allow all if policy is 'none' # if test $mypolicy = "none" { for ip in [$iplist] { setvar daddr = $(get_IP ${ip}) test -z $daddr -o $daddr = '""' && continue echo "pass in log quick proto ${proto} from any to ${daddr}" \ "port = ${port} ${tcp_opts}" >>${out} } return 0 } # # For now, let's concern ourselves only with incoming traffic. # test $mypolicy = "deny" && do { setvar ecmd = ""pass""; setvar acmd = ""block ${block_policy}""; } test $mypolicy = "allow" && do { setvar ecmd = ""block ${block_policy}""; setvar acmd = ""pass""; } for name in [$(get_exceptions${_6} $service)] { test -z $name -o $name = '""' && continue setvar ifc = $(get_interface $name) if test $Status -eq 0 -a -n $ifc { for ip in [$iplist] { setvar daddr = $(get_IP ${ip}) test -z $daddr -o $daddr = '""' && continue echo "${ecmd} in log quick on ${ifc} from any to" \ "${daddr} port = ${port}" >>${out} } continue } setvar saddr = $(get_IP ${name}) if test $Status -eq 0 -a -n $saddr { for ip in [$iplist] { setvar daddr = $(get_IP ${ip}) test -z $daddr -o $daddr = '""' && continue echo "${ecmd} in log quick proto ${proto} from ${saddr}" \ "to ${daddr} port = ${port} ${tcp_opts}" >>${out} } } } for name in [$(get_apply2${_6}_list $service)] { test -z $name -o $name = '""' && continue setvar ifc = $(get_interface $name) if test $Status -eq 0 -a -n $ifc { for ip in [$iplist] { setvar daddr = $(get_IP ${ip}) test -z $daddr -o $daddr = '""' && continue echo "${acmd} in log quick on ${ifc} from any to" \ "${daddr} port = ${port}" >>${out} } continue } setvar saddr = $(get_IP ${name}) if test $Status -eq 0 -a -n $saddr { for ip in [$iplist] { setvar daddr = $(get_IP ${ip}) test -z $daddr -o $daddr = '""' && continue echo "${acmd} in log quick proto ${proto} from ${saddr}" \ "to ${daddr} port = ${port} ${tcp_opts}" >>${out} } } } for ip in [$iplist] { setvar daddr = $(get_IP ${ip}) test -z $daddr -o $daddr = '""' && continue echo "${ecmd} in log quick proto ${proto} from any to ${daddr}" \ "port = ${port} ${tcp_opts}" >>${out} } return 0 } # # Service has either IANA ports and proto or its own firewall method to # generate the rules. # # - if service has a custom method, use it to populate its rules # - if service has a firewall_config pg, use process_server_svc # # Argument - fmri # proc process_service { # # Don't process network/ipfilter # test $1 = $IPF_FMRI && return 0 service_check_state $1 $SMF_MAINT && return 1 setvar method = $(svcprop -p $FW_CONTEXT_PG/$METHOD_PROP $1 2>/dev/null | \ sed 's/\\\//g) if test -n $method -a $method != '""' { shell { exec $method $1 >/dev/null } } else { svcprop -p $FW_CONFIG_PG $1 >/dev/null 2>&1 || return 1 process_server_svc $1 || return 1 } return 0 } # # Generate rules for protocol/port defined in firewall_config_default/open_ports # property. These are non-service programs whose network resource info are # defined as "{tcp | upd}:{PORT | PORT-PORT}". Essentially, these programs need # some specific local ports to be opened. For example, BitTorrent clients need to # have 6881-6889 opened. # proc process_nonsvc_progs { setvar out = "$1" echo "# Non-service programs rules" >>${out} setvar progs = $(global_get_prop_value $FW_CONFIG_DEF_PG $OPEN_PORTS_PROP) for prog in [$progs] { test -z $prog -o $prog = '""' && continue setvar port = $(tuple_get_port $prog) test $Status -eq 1 -o -z $port && continue setvar proto = $(tuple_get_proto $prog) test $Status -eq 1 && continue set -- $port if test $Argc -gt 1 { if test -z $proto { echo "pass in log quick from any to any" \ "port ${1} >< ${2}" >>${out} } else { echo "pass in log quick proto ${proto} from any" \ "to any port ${1} >< ${2}" >>${out} } } else { if test -z $proto { echo "pass in log quick from any to any" \ "port = ${1}" >>${out} } else { echo "pass in log quick proto ${proto} from any" \ "to any port = ${1}" >>${out} } } } return 0 } # # Generate a new /etc/ipf/ipf.conf. If firewall policy is 'none', # ipf.conf is empty . # proc create_global_rules { if test $GLOBAL_POLICY = "custom" { setvar file = $(global_get_prop_value $FW_CONFIG_DEF_PG $CUSTOM_FILE_PROP) setvar file6 = $(global_get_prop_value $FW_CONFIG_DEF_PG $CUSTOM_FILE_6_PROP) test -n $file && custom_set_symlink $file test -n $file6 && custom_set_symlink_6 $file6 return 0 } setvar TEMP = $(mktemp /var/run/ipf.conf.pid$Pid.XXXXXX) setvar TEMP6 = $(mktemp /var/run/ipf6.conf.pid$Pid.XXXXXX) process_nonsvc_progs $TEMP process_nonsvc_progs $TEMP6 echo "# Global Default rules" >>${TEMP} echo "# Global Default rules" >>${TEMP6} if test $GLOBAL_POLICY != "none" { echo "pass out log quick all keep state" >>${TEMP} echo "pass out log quick all keep state" >>${TEMP6} } match $GLOBAL_POLICY { with 'none' # No rules replace_file ${IPFILCONF} ${TEMP} replace_file ${IP6FILCONF} ${TEMP6} return $? with 'deny' setvar ecmd = ""pass"" setvar acmd = ""block"" with 'allow' setvar ecmd = ""block"" setvar acmd = ""pass"" with * return 1; } for name in [$(global_get_prop_value $FW_CONFIG_DEF_PG $EXCEPTIONS_PROP)] { test -z $name -o $name = '""' && continue setvar ifc = $(get_interface $name) if test $Status -eq 0 -a -n $ifc { echo "${ecmd} in log quick on ${ifc} all" >>${TEMP} continue } setvar addr = $(get_IP ${name}) if test $Status -eq 0 -a -n $addr { echo "${ecmd} in log quick from ${addr} to any" >>${TEMP} } } for name in [$(global_get_prop_value $FW_CONFIG_DEF_PG $EXCEPTIONS_6_PROP)] { test -z $name -o $name = '""' && continue setvar ifc = $(get_interface $name) if test $Status -eq 0 -a -n $ifc { echo "${ecmd} in log quick on ${ifc} all" >>${TEMP6} continue } setvar addr = $(get_IP ${name}) if test $Status -eq 0 -a -n $addr { echo "${ecmd} in log quick from ${addr} to any" >>${TEMP6} } } for name in [$(global_get_prop_value $FW_CONFIG_DEF_PG $APPLY2_PROP)] { test -z $name -o $name = '""' && continue setvar ifc = $(get_interface $name) if test $Status -eq 0 -a -n $ifc { echo "${acmd} in log quick on ${ifc} all" >>${TEMP} continue } setvar addr = $(get_IP ${name}) if test $Status -eq 0 -a -n $addr { echo "${acmd} in log quick from ${addr} to any" >>${TEMP} } } for name in [$(global_get_prop_value $FW_CONFIG_DEF_PG $APPLY2_6_PROP)] { test -z $name -o $name = '""' && continue setvar ifc = $(get_interface $name) if test $Status -eq 0 -a -n $ifc { echo "${acmd} in log quick on ${ifc} all" >>${TEMP6} continue } setvar addr = $(get_IP ${name}) if test $Status -eq 0 -a -n $addr { echo "${acmd} in log quick from ${addr} to any" >>${TEMP6} } } if test $GLOBAL_POLICY = "allow" { # # Allow DHCP(v6) traffic if running as a DHCP client # /sbin/netstrategy | grep dhcp >/dev/null 2>&1 if test $Status -eq 0 { echo "pass out log quick from any port = 68" \ "keep state" >>${TEMP} echo "pass in log quick from any to any port = 68" >>${TEMP} echo "pass out log quick from any port = 546" \ "keep state" >>${TEMP6} echo "pass in log quick from any to any port = 546" >>${TEMP6} } echo "block in log all" >>${TEMP} echo "block in log all" >>${TEMP6} } replace_file ${IPFILCONF} ${TEMP} replace_file ${IP6FILCONF} ${TEMP6} return $? } # # Generate a new /etc/ipf/ipf_ovr.conf, the override system-wide policy. It's # a simplified policy that doesn't support 'exceptions' entities. # # If firewall policy is "none", no rules are generated. # # Note that "pass" rules don't have "quick" as we don't want # them to override services' block rules. # proc create_global_ovr_rules { # # Simply empty override file if global policy is 'custom' # if test $GLOBAL_POLICY = "custom" { echo "# 'custom' global policy" >$IPFILOVRCONF echo "# 'custom' global policy" >$IP6FILOVRCONF return 0 } # # Get and process override policy # setvar ovr_policy = $(global_get_prop_value $FW_CONFIG_OVR_PG $POLICY_PROP) if test $ovr_policy = "none" { echo "# global override policy is 'none'" >$IPFILOVRCONF echo "# global override policy is 'none'" >$IP6FILOVRCONF return 0 } setvar TEMP = $(mktemp /var/run/ipf_ovr.conf.pid$Pid.XXXXXX) test $ovr_policy = "deny" && setvar acmd = ""block in log quick"" test $ovr_policy = "allow" && setvar acmd = ""pass in log"" setvar apply2_list = $(global_get_prop_value $FW_CONFIG_OVR_PG $APPLY2_PROP) for name in [$apply2_list] { test -z $name -o $name = '""' && continue setvar ifc = $(get_interface $name) if test $Status -eq 0 -a -n $ifc { echo "${acmd} on ${ifc} all" >>${TEMP} continue } setvar addr = $(get_IP ${name}) if test $Status -eq 0 -a -n $addr { echo "${acmd} from ${addr} to any" >>${TEMP} } } setvar apply2_6_list = $(global_get_prop_value $FW_CONFIG_OVR_PG $APPLY2_6_PROP) for name in [$apply2_6_list] { test -z $name -o $name = '""' && continue setvar ifc = $(get_interface $name) if test $Status -eq 0 -a -n $ifc { echo "${acmd} on ${ifc} all" >>${TEMP6} continue } setvar addr = $(get_IP ${name}) if test $Status -eq 0 -a -n $addr { echo "${acmd} from ${addr} to any" >>${TEMP6} } } replace_file ${IPFILOVRCONF} ${TEMP} replace_file ${IP6FILOVRCONF} ${TEMP6} return $? } # # Service is put into maintenance state due to its invalid firewall # definition and/or policy. # proc svc_mark_maintenance { svcadm mark maintenance $1 >/dev/null 2>&1 setvar date = $(date) echo "[ $date ${0}: $1 has invalid ipf configuration. ]" echo "[ $date ${0}: placing $1 in maintenance. ]" # # Move service's rule files to another location since # they're most likely invalid. # setvar ipfile = $(fmri_to_file $1 $IPF_SUFFIX) test -f $ipfile && mv $ipfile "$ipfile.bak" setvar ip6file = $(fmri_to_file $1 $IPF6_SUFFIX) test -f $ip6file && mv $ip6file "$ip6file.bak" setvar natfile = $(fmri_to_file $1 $NAT_SUFFIX) test -f $natfile && mv $natfile "$natfile.bak" return 0 } proc svc_is_server { svcprop -p $FW_CONFIG_PG $1 >/dev/null 2>&1 } # # Create rules for enabled firewalling and client services. # - obtain the list of enabled services and process them # - save the list of rules file for later use # proc create_services_rules { # # Do nothing if global policy is 'custom' # test $GLOBAL_POLICY = "custom" && return 0 ipf_get_lock # # Get all enabled services # setvar allsvcs = $(svcprop -cf -p general/enabled -p general_ovr/enabled '*' \ 2>/dev/null | sed -n 's,^\(svc:.*\)/:properties/.* true$,\1,p' | sort -u) # # Process enabled services # for s in [$allsvcs] { service_is_enabled $s || continue process_service $s || continue setvar ipfile = $(fmri_to_file $s $IPF_SUFFIX) if test -n $ipfile -a -r $ipfile { check_ipf_syntax $ipfile if test $Status -ne 0 { svc_mark_maintenance $s continue } svc_is_server $s if test $Status -eq 0 { check_ipf_rules $ipfile if test $Status -ne 0 { svc_mark_maintenance $s continue } } setvar CONF_FILES = ""$CONF_FILES $ipfile"" } setvar ip6file = $(fmri_to_file $s $IPF6_SUFFIX) if test -n $ip6file -a -r $ip6file { check_ipf_syntax $ip6file -6 if test $Status -ne 0 { svc_mark_maintenance $s continue } svc_is_server $s if test $Status -eq 0 { check_ipf_rules $ip6file -6 if test $Status -ne 0 { svc_mark_maintenance $s continue } } setvar CONF6_FILES = ""$CONF6_FILES $ip6file"" } setvar natfile = $(fmri_to_file $s $NAT_SUFFIX) if test -n $natfile -a -r $natfile { check_nat_syntax $natfile if test $Status -ne 0 { svc_mark_maintenance $s continue } setvar NAT_FILES = ""$NAT_FILES $natfile"" } } ipf_remove_lock return 0 } # # We update a services ipf ruleset in the following manners: # - service is disabled, tear down its rules. # - service is disable or refreshed(online), setup or update its rules. # proc service_update_rules { setvar svc = "$1" setvar ipfile = $(fmri_to_file $svc $IPF_SUFFIX) setvar ip6file = $(fmri_to_file $svc $IPF6_SUFFIX) test -n $ipfile && remove_rules $ipfile test -n $ip6file && remove_rules $ip6file -6 test -z $ipfile -a -z $ip6file && return 0 setvar natfile = $(fmri_to_file $svc $NAT_SUFFIX) test -n $natfile && remove_nat_rules $natfile # # Don't go further if service is disabled or in maintenance. # service_is_enabled $svc || return 0 service_check_state $1 $SMF_MAINT && return 0 process_service $svc || return 1 if test -f $ipfile { check_ipf_syntax $ipfile if test $Status -ne 0 { svc_mark_maintenance $svc return 1 } } if test -f $ip6file { check_ipf_syntax $ip6file -6 if test $Status -ne 0 { svc_mark_maintenance $svc return 1 } } if test -f $natfile { check_nat_syntax $natfile if test $Status -ne 0 { svc_mark_maintenance $svc return 1 } } if test -f $ipfile { svc_is_server $svc if test $Status -eq 0 { update_check_ipf_rules $ipfile if test $Status -ne 0 { svc_mark_maintenance $svc return 1 } } prepend_new_rules $ipfile # # reload Global Override rules to # maintain correct ordering. # remove_rules $IPFILOVRCONF prepend_new_rules $IPFILOVRCONF } if test -f $ip6file { svc_is_server $svc if test $Status -eq 0 { update_check_ipf_rules $ip6file -6 if test $Status -ne 0 { svc_mark_maintenance $svc return 1 } } prepend_new_rules $ip6file -6 # # reload Global Override rules to # maintain correct ordering. # remove_rules $IP6FILOVRCONF -6 prepend_new_rules $IP6FILOVRCONF -6 } test -f $natfile && append_new_nat_rules $natfile return 0 } # # Call the service_update_rules with appropriate svc fmri. # # This is called from '/lib/svc/method/ipfilter fw_update' whenever # a service is disabled/enabled/refreshed. # proc service_update { setvar svc = "$1" setvar ret = '0' # # If ipfilter isn't online or global policy is 'custom', # nothing should be done. # test $GLOBAL_POLICY = "custom" && return 0 service_check_state $SMF_FMRI $SMF_ONLINE || return 0 ipf_get_lock service_update_rules $svc || setvar ret = '1' ipf_remove_lock return $ret } # # Initialize global configuration # global_init